Domain-Driven design en continu
Au-delà de l'Event-Storming
C'est quoi le Domain-Driven Design ?
C'est quoi le Domain-Driven Design ?
Favoriser le partage de connaissance métier entre les experts et les tech
C'est quoi le Domain-Driven Design ?
Le langage ubiqutaire
Le jargon commun entre les experts et les tech
C'est quoi le Domain-Driven Design ?
Langage valide au sein d'un context précis
C'est quoi L'Event Storming ?
It’s not stakeholder knowledge but developers' ignorance that gets deployed into production
— Alberto Brandolini
C'est quoi L'Event Storming ?
C'est quoi L'Event Storming ?
Loïc Broquet
lolo101
Once upon a time
Green field
Event Storming
Premiers jours
Mais après quelques mois
Mais après quelques mois
Mais après quelques mois
On a perdu l'expertise métier
Et on a des bugs
29%
31%
Rendre le code défensif
Sonar
- Test coverage
- Code smells
- Bogus code
- Security vulnerabilities
JetBrains Qodana
- Code smells
- Bogus code
- IDE integration
Rendre le code défensif
CodeScene
- Hot spots
- Code health
- Teams topology
Rendre le code défensif
Renforcer la compréhension du domaine métier
Quels outils ?
Renforcer la compréhension du domaine métier
Mais
J'aimerais un indicateur qui m'aide à remplacer
Ce code
public double calculatePrice(Collection<Item> items, int discount, int vat) {
double price = 0;
for (Item item : items) {
price += item.price;
}
double discountedPrice = price * ( 1 - discount / 100.0);
double netPrice = discounterPrice * (1 + vat / 100.0);
return netPrice;
}
💀 Item.price < 0 ?
NaN ?
discount < 0 ? > 100 ?
On a inversé discount et vat ?
Par ce code
public record Amount(BigDecimal value) {
public Amount {
if (value.compareTo(BigDecimal.ZERO) < 0) {
throw new NegativeAmount(value);
}
}
}
public record Price(Amount amount, Currency currency) {}
public Price calculatePrice(Basket basket, Discount discount, Vat vat) {
Price rawPrice = basket.totalPrice();
Price discountedPrice discount.appliedTo(rawPrice);
Price netPrice = vat.appliedTo(discountedPrice);
return netPrice;
}
Le nuage c'est bien mais
pour quantifier,
la liste des mots c'est mieux !
# list java files in "service" or "domain" packages, excluding tests
find "../$PROJECT" -type f -not -path "*/test/*" \( -path "*/service/*" -o -path "*/domain/*" \) -name "*.java"
# concatenate files contents
| xargs sed
# remove comment blocs
-e '/\/\*/,/\*\//d'
# remove comment lines
-e 's/\/\/.*$//g'
# remove imports section
-e '/^import /d'
# remove package declaration
-e '/^package /d'
# replace non-identifiers symbols with linefeeds
-e 's/[^A-Za-z0-9_]/\n/g'
# remove empty lines
| grep .
# convert to lowercase
| tr '[:upper:]' '[:lower:]'
# sort alphabetically
| sort
# distinct and count
| uniq -c
# sort by number of occurrences
| sort -nr
~50 ms / 30 kloc !
Introducing indddy v1
Mesurer Le lexique ubiquitaire Dans le code
Définir le lexique
Mesurer Le lexique ubiquitaire Dans le code
Catégoriser les mots
Mesurer Le lexique ubiquitaire Dans le code
Calculer un score
Attention le langage nous impose des keywords
(class, public, return, etc.)
Il faut choisir soigneusement ceux qu'on ignore
Un "bon" score est 50% ou plus
Tech Lead
Tech Lead
On a un score de 30%
mais on ne sait pas comment l'améliorer
L'indicateur DDD, on ne le suit plus parce qu'on ne tirait pas d'action
Event Storming ?
C'est quoi ?
Tech Lead
Difficile d'emporter l'adhesion
Effort récurrent
Pas automatisable
Difficile d'emporter l'adhesion
Effort récurrent
Pas automatisable
On ne maintient plus
le langage ubiquitaire
=> Supporter de nouveaux langages
=> Maintenabilité de l'indicateur
=> L'indicateur devient entièrement automatisable
Trade-off
Time
Mesure de la
primitive obsession
Abandon du script ultra rapide
On se base sur un AST JavaScript
Introducing Indddy v2
~600 ms / 30 kloc
Mesurer La primitive obsession
L'indicateur est beaucoup moins bruité puisqu'il ne sélectionne que les types
Un "bon" score est 20% ou moins
Introducing Indddy v2
Mine de rien c'est déjà une innovation !
Conclusion
Conclusion
Conclusion
# list java files in "service" or "domain" packages, excluding tests
find "../$PROJECT" -type f -not -path "*/test/*" \( -path "*/service/*" -o -path "*/domain/*" \) -name "*.java"
# concatenate files contents
| xargs sed
# remove comment blocs
-e '/\/\*/,/\*\//d'
# remove comment lines
-e 's/\/\/.*$//g'
# remove imports section
-e '/^import /d'
# remove package declaration
-e '/^package /d'
# replace non-identifiers symbols with linefeeds
-e 's/[^A-Za-z0-9_]/\n/g'
# remove empty lines
| grep .
# convert to lowercase
| tr '[:upper:]' '[:lower:]'
# sort alphabetically
| sort
# distinct and count
| uniq -c
# sort by number of occurrences
| sort -nr
Conclusion
Vision
Un indicateur de primitive obsession
Support de Kotlin, Typescript
Inférence de langage ubiquitaire avec LLM + RAG
(Retrieval-Augmented Generation)
Inclus dans la pipeline d'intégration continue (CI)
"Domain-driven Sonar"
Ressources
https://github.com/lolo101/indddy
Votre avis compte !
https://openfeedback.io/dd2024/2024-11-07/639461
Dépasser les Limites de l'Event Storming
By Loïc Broquet
Dépasser les Limites de l'Event Storming
- 28