JTC 2024 - Réglementation européenne BEA et Transport.pdf
DDD, CQRS et Event Sourcing : quand coder propre n'est plus suffisant
1. DDD, CQRS et Event Sourcing :
quand coder propre n'est pas
sufsant
Joseph Pachod
https://twitter.com/joeclueless
2. Coder propre nécessaire mais...
Coder propre : plein de règles applicables
localement, bien moins à l'échelle d'une application.
3. Capture du métier ?
Comment capturer le métier ?
● couches techniques souvent plus simples à
organiser
● Conservation des connaissances métier de façon
pérenne ?
5. Eric Evans
Domain-Driven Design: Tackling Complexity in the
Heart of Software – 2004
What I've learned about DDD since the book – 2009
Livre clé, aujourd'hui un peu dépassé sur certains
points (dixit Evans lui même)
Auteur a longuement pratiqué son approche avant
que Martin Fowler ne vienne travailler avec lui et le
convainque d'écrire un livre et communiquer sur celle
ci, nommée Domain Driven Design à l'occasion.
7. Ubiquitous Language
(Langage omniprésent)
Langage des experts du domaine, utilisé également
par les développeurs et dans le modèle, c'est à dire le
code.
Nécessité de bien se comprendre et de reporter cela
jusque dans le code.
Le modèle doit communiquer comment fonctionne le
domaine, afn de faciliter sa compréhension et sa
mise en œuvre.
8. A utiliser tout le temps
Rendre l'implicite explicite
Dans le code et à l'oral
● Précision du langage
● Capacité à détecter les problèmes
Si quelque chose sonne faux dans le langage
omniprésent : revoir le vocabulaire et refactorer
Rendre l'implicite explicite
- faire ressortir les concepts
- écouter le langage des utilisateurs experts (mots
succincts pour des choses compliquées, correction
du vocable des développeurs, éclairs de
compréhension avec certains mots)
- examiner les maladresses
- réféchir sur les contradictions
- apprendre le domaine fonctionnel
9. Hands on modelers
(Concepteurs les mains dans le code)
Le code est primordial pour valider le modèle et les
refactoring, il faut que ceux qui modélisent touchent
également au code. Ce dernier fait alors ofce de
garde fou, rappelant les réalités du modèle, mais
sert également à valider les changements.
Garanti la pérennité du modèle, qui ne peut pas
diverger du code s'il est directement dans le code.
10. Mise en œuvre "tactique"
Eric Evans parle « tactique »
Mise en œuvre reprise parfois au pied de la lettre,
notamment en .Net
11. Modélisation "tactique"
au choix de l'équipe
Cf par exemple « Functional and Reactive Domain
Modeling » (voir le livre du même nom pour plus de
détails).
14. Refactoring continu
Le refactoring continu assure que le code refète
toujours bien le langage omniprésent.
Qui plus est, le refactoring améliore la proximité avec
le code, permettant de mieux en saisir le modèle et
les nuances.
Avec le temps, il arrive ce qu'Eric Evans nomme des
percées : des éclairs de compréhension du
domaine qui se répercutent par des changements
signifcatifs du modèle. Bien souvent des aspects
pénibles du modèle sont alors supprimés et
d'anciennes incompréhensions ou incohérences
s'expliquent.
15. Préserver l'intégrité du modèle
quand la complexité croît
Même termes, usages diférents, modélisation variant
à terme
Cohésion et unicité du langage omniprésent mis en
péril dès que le nombre d'interlocuteurs augmente
Coût de la coordination
Un modèle unique pour tout le logiciel est difcile,
voir utopique
Quid de l'interfaçage avec du code tiers ?
17. Bounded context
(Contexte borné)
Défnir les limites précises, quels concepts sont
inclus, quels besoins.
Le contexte borné doit protéger son modèle du reste
du code, l'isolant afn de pouvoir le faire évoluer
sans nécessairement impacter le reste du monde,
sauf pour des contextes bien identifés.
Une équipe peut travailler sur plusieurs contextes, un
contexte ne peut être manipulé que par une équipe.
22. Context map
(Carte de contexte)
Identife les diférents contextes bornés et leurs
relations.
Les noms des contextes font partie du langage
omniprésent, facilitant grandement les discussions.
Plusieurs types d'interactions entre contextes
possibles, existence de pattern
23. Distiller pour aller à l'essentiel
En introduisant des sous domaines génériques pour
garder le domaine essentiel au coeur.
Sortir des mécanismes cohérents en soi du domaine
pour les mettre dans des librairies.
24. Core domain with a vision statement
(Domaine central avec une vision)
Il convient d’identifer le ou les domaines centraux de
l’entreprise.
Il s’agit généralement de ceux les plus proftables.
Eric Evants préconise de leur associer une « vision
claire », c’est à dire une phrase résumant leur
nature et leur objectif, afn de s’assurer de ne pas
en diverger par accident.
Il faut également attribuer à ces domaines le plus de
ressources notamment :
- privilégier les domaines centraux dans les
arbitrages,
- y afecter les meilleurs développeurs.
27. Cas des Frenchies
(et autres non anglophones)
Comment faire quand on code dans un langage
informatique en anglais et que les utilisateurs
parlent français, voir également allemand ?
Choisir le langage de référence, celui utilisé par les
experts du domaine
28. Avoir des domaines pérennes
Les diférentes couches Domaine représentent le
coeur de métier d’une entreprise.
Leur durée de vie est souvent bien plus grande que
celle des technologies utilisées.
Il se peut même qu’il faille un jour porter ces règles
métier sur une autre plateforme, par exemple dans
une application mobile supportant un mode
déconnecté.
Aussi, il est important que l’adhérence des couches
domaines au langage et aux outils utilisées soit
contenue, afn de pouvoir aisément basculer sur de
nouvelles technologies.
30. Mais...
tout le métier est dans un même
processus
Tout le métier peut appeler tout le métier
● Tout peut dépendre de tout
● Complexité résultante importante
● Une erreur, même émanant d'une tâche sans
importance, peut planter toute l'application (Out Of
Memory en Java par exemple).
32. The database is a subset of the logs
(La base de données contient un sous
ensemble des traces)
Une base de données peut être utilisée de façon à
mettre à jour les données. Autrement dit, si un
utilisateur change de nom, on met à jour la ligne
correspondante. On parle alors d'« update in
place ».
Ce faisant, toutefois, on perd l'ancien nom.
Et peut être a t on plus d'informations dans les
fchiers de logs : valeur du nouveau nom, de
l'ancien, date de mise à jour...
Au fnal, alors qu'on a une base de données avec
plein de fonctionnalités, une bonne partie des infos
se trouvent dans des fchiers textes plus durs à
exploiter et souvent non conservés...
33. Quid du monde réel ?
Pas de mise à jour, seulement des événements.
Date et données d'un événement ne changent pas.
Seuls de nouveaux événements s'ajoutent.
34. Evénement : date et données
Idées :
● stocker les événements
● construire l'état courant à partir des événements
43. Découplage fort
● L'émetteur de l'événement ignore tout des
souscripteurs, l'événement est le seul contrat à
honorer
=> piles techniques diférentes possibles, ouverture
sur le reste du monde
44. Events Log
Conservation des événements suite
à leur publication
● historique du système
● capacité à rejouer tout ou partie
● consommation décalée possible
46. Retour au Domain Driven Design
Événements pour échanger entre contextes bornés
Vues pour mieux servir les lectures du domaine
Code des contextes vraiment indépendant les uns
des autres, voir même les piles techniques
Historique
47. Domain Events
On en reparle dans la suite : Eric Evans s'inspire des
mêmes éléments pour recommander les Domain
Events
49. CQRS
Command And Query Responsibility
Segregation
(Ségrégation des Responsabilités de
Commande et de Requête)
50. Base de données
=
goulet d'étranglement
Constat : la base de données est un goulet
d'étranglement des performances et de la
modélisation
51. Une base de données peut
consommer 80% du CPU pour la
gestion des transactions.
52. Séparer lecture et écriture
Écriture (Write side – Command) : une base de
données
Lecture (Read side - Request) : réplication de la base
d'écriture vers une ou plusieurs bases de données
On évoque généralement un facteur 100 en termes
de gain de charge.
53. Pourquoi garder un même modèle ?
Par exemple si présence d’une notion d’utilisateur.
Lors de l’ajout d’un utilisateur, il faut :
- s’assurer de l’unicité du login
- s’assurer de la présence de certains champs
Seule l’unicité du login nécessite un état en base, le
reste ne nécessite pas des données persistentes
pour pouvoir être contrôlé.
A l’inverse un afchage d’utilisateurs requiert souvent
des jointures mais pas le login…
=> les besoins en lecture et écriture sont très
diférents : un même modèle implique des
compromis
54. Write & Read Model
(Modèles d'écriture et de lecture)
Le Write model sera :
● Centré sur les invariants lors de l'écriture
● Granularité fne
● Charge limitée
● Besoin d'un support des transactions
=> bases relationnelles bonnes candidates
Le Read model :
● Pas besoin de transactions
● Possibilité d’aggrégations
● Charge bien plus importante
=> nombreuses solutions possibles (NoSQL...)
55. Retour à l'Event Sourcing
Les écritures partagent beaucoup avec les
événements.
Similitudes
● Ecriture à date donnée
● Contiennent des données exprimant une demande
Diférences
● Peuvent échouer
● S'ils réussissent, déclenchent des événements
56. Commande
Date, données, consommation
unique
Peut échouer
Introduction de la notion de commande :
● Une date
● Une demande exprimée par les données
● Peut réussir ou non
● Consommation unique : un seul service doit
décider de son succès ou non.
57. Granularité fne des changements
Changements via des commandes, non des entités :
on peut aisément ne changer qu'une valeur, pas
besoin de tout transporter.
58. Ébauche d'une réponse au
problème initial
● Capture du métier via le langage omniprésent
● Intégrité assurée via les contextes bornés
● Les contextes valident les commandes et émettent
les événements
● Les vues agrègent les événements et permettent la
lecture
62. Consistance souvent illusoire
Écrans non rafraîchis
Transactions consécutives
Cache divers
Systèmes non entièrement transactionnels
Niveau d'isolation des transactions baissé pour
raisons de performances
63. Au niveau de l'interface utilisateur
Bloquer en attendant les résultats
Indiquer l'en cours
Combiner les deux...
64. Initialement…
un monolithe !
Tout dans un processus
● Appels synchrones
● Quid de plusieurs nœuds (performance,
redondance) ?
Une couche métier
● Tout le code métier peut appeler tout le code métier
● Pas de séparation physique du code métier.
● Chaque entité ou concept est susceptible d'être
utilisé dans n'importe quel autre bout de code,
même pour des besoins divergeant.
Une base de donnés
● Compromis entre les diférents besoin métier
● Goulet d'étranglement
Framework
● Quid si évolue dans un sens non désiré ?
● Quid s'il n'est plus maintenu ?
65. Monolithe
=
coûts exponentiels avec le temps
Montées en charge difcile
● Du nombre d'utilisateur
● Du nombre de fonctionnalités
● Du nombre de développeurs
Utilisation de systèmes tiers non prévue
67. Microservices ?
Défnition exacte d’un microservices compliquée
mais :
- synchrone ou asynchrone
- portée d’un microservice très limitée
-- fait juste une chose (que le transport, que la
transformation, que la …)
Netfix : 1/3 du trafc internet, plus de 1000
microservices
76. Pour approfondir
● Event Sourcing : Talks de Rich Hickey
● CQRS : Talks de Greg Young
● Stream Processing :
The Log: What every software engineer should know about real-time data's unifying
abstraction
● Documentation Kafka
● Analyses de systèmes distribués
● Fallacies of Distributed Computing Explained
● Domain-Driven Design Vite fait
● Clarifed CQRS
● Designing Data-Intensive Application
Frameworks/librairies souvent trop générales
Approfondir via des implémentations d'event bus
(Kafka )
77. Remerciements
Eric Evans, Rich Hickey, Greg Young : penseurs des concepts présentés
A tous ceux avec qui j’ai pu discuter et approfondir les concepts, dont
- Uwe Schäfer (@codesmell)
- Olivier Schneider (@Oli3dfx)
A vous, pour être venu et avoir tenu si longtemps