SlideShare a Scribd company logo
1 of 52
Download to read offline
Implémentation efficace et durable de processus
métiers complexes
Gérard Dethier
15 janvier 2021 / Geeks Anonymes Liège
https://www.gerarddethier.be
Résumé de l’épisode précédent...
https://www.youtube.com/watch?v=OmrtGo68E6M
Tout est processus...
▶
La majorité des systèmes IT implémentent des processus
métier
▶
L’implémentation implique le stockage d’un état (les
données)
▶
L’état évolue par réaction à des stimuli (des commandes
soumises par les utilisateurs)
Une exécution efficace est importante
▶
L’exécution d’un grand nombre de transactions par unité
de temps est parfois nécessaire
▶
Ces transactions peuvent devoir être exécutées en
parallèle
▶
« Time is money »
La maintenabilité est essentielle
▶
Les conditions évoluent
▶
Besoins (métier)
▶
Attentes (utilisateurs)
▶
Équipes (composition)
Le Domain-Driven Design apporte des outils
▶
Domain-Driven Design = DDD
▶
Un langage commun entre développeurs et experts du domaine
▶
Le code est un modèle de la réalité du terrain
▶
Des règles de conception favorisant
▶
maintenabilité
▶
efficacité
▶
robustesse
DDD dans une coquille de noix
DDD est une méthodologie de modélisation
▶
Développeurs et experts coconstruisent un modèle abstrait
▶
DDD fournit des composants de base
▶
Ils utilisent un langage commun
▶
Le Ubiquitous Language
▶
Le modèle est descriptible à l’aide de code
Les composants ont différentes caractéristiques
▶
État
▶
Représentation des données
▶
Les données sont immuables ou non
▶
Maintient des contraintes liées aux données
▶
Comportement
▶
Opérations pouvant impliquer l’état
▶
Structure
▶
Regroupement d’autre composants
▶
Stratégie
▶
Possibilité de raisonner sur des systèmes « morcelés » et à grande échelle
Les composants avec un état
▶
Value Object (VO)
▶
Données immuable
▶
Le comportement n’altère pas l’état
▶
Entity
▶
Données non-immuables
▶
Le comportement peut altérer l’état
▶
Domain event (ou event)
▶
Permet le transport de données
▶
Pas de comportement
Aggregate et composants liés
▶
Aggregate
▶
Graphe d’Entities et VOs liés par un ensemble de contraintes fortes
▶
Accès uniquement via l’Aggregate Root (= Entity garantissant le respect des contraintes)
▶
Factory
▶
Produit des Aggregates
▶
Les contraintes sont respectées initialement
▶
Repository
▶
Stocke et récupère des Aggregates
▶
Les contraintes sont respectées au moment du stockage et lors de la récupération
Le Module
▶
Composant structurant
▶
Définit un espace de nommage pour
▶
Aggregates
▶
Entities
▶
VOs
Autres composants
▶
Service
▶
Pas d’état
▶
Comportement qui ne peut être mis ailleurs
▶
Bounded Context
▶
Stratégie
▶
Partition d’un système
▶
Peut contenir un ou plusieurs Modules, voir des fragments
▶
Context Map
▶
Graphe liant les Bounded Contexts
▶
Lien = dépendance (librairies), transport de données (event ou autre)
Quelques règles de conception...
▶
Un seul Aggregate mis à jour par transaction
▶
Les règles de consistance portant sur plusieurs
Aggregates sont implémentées à l’aide Events
▶
Les Aggregates doivent être les plus petits possibles
▶
Le code documente le modèle implémenté
▶
Conventions de nommage
▶
Utilisation du Ubiquitous Language
Appliquer DDD n’est pas toujours simple
▶
Bonne connaissance théorique requise
▶
Trop abstrait pour les experts métier
▶
Pas assez concret pour les développeurs
▶
Implique la résolution de difficultés techniques
▶
Séparation claire entre modèle et détails techniques
▶
Dans un contexte distribué, transport et traitement des
événements
Un petit « pousse » pour digérer
tout cela ?
Pousse-Café (PC) est un framework...
▶
Java (11+)
▶
Libre et open-source (Apache 2.0)
▶
Léger
▶
Modulaire
▶
Facilitant...
▶
l’implémentation efficace de processus complexes
▶
l’abstraction du stockage et du transport des données
▶
une bonne communication entre développeurs et experts métier
PC interprète le DDD dans l’« univers » Java
▶
Classes
▶
VOs
▶
Entities
▶
Factories
▶
Repositories
▶
Services
▶
Aggregates
▶
Interfaces
▶
Events
▶
Modules
PC introduit quelques éléments supplémentaires
▶
Les Commands
▶
Requêtes soumises par les utilisateurs
▶
Définies par une classe ou une interface
▶
Les Processes
▶
Interfaces nommant et décrivant des processus métiers
▶
Les Listeners
▶
Méthodes traitant Event ou Command
▶
Liés à un ou plusieurs Processes
PC fournit un Runtime
▶
Charge un ensemble défini de composants au démarrage
▶
Reçoit des Commands
▶
Consomme les Events à partir d’un bus de communication
▶
Pour chaque Command/Event traité
▶
détermine le(s) Aggregates à créer/mettre à jour/supprimer
▶
exécute les Listeners des Aggregate Roots, Factories et Repositories
▶
sauvegarde les changements et publie les Events potentiellement émis
Comment décrit-on un processus
métier avec PC ?
Il y a quelques étapes...
▶
Définir le Process
▶
Définir les Aggregates
▶
Aggregate Roots
▶
Factories
▶
Repositories
▶
Définir les Commands et Events
▶
Créer les Listeners et les lier au Process
Exemple : ProductManagement
▶
Domaine : plateforme de e-commerce
▶
Portée
▶
Création d’un produit sans stock
▶
Ajout d’unités au stock
▶
État
▶
Un Aggregate → Product
Définition du Process ProductManagement
public interface ProductManagement extends Process {
}
Définition de l’Aggregate Product
@Aggregate
public class Product {
public static class Factory extends AggregateFactory<ProductId, Root, Root.Attributes> {
}
public static class Root extends AggregateRoot<ProductId, Root.Attributes> {
public static interface Attributes extends EntityAttributes<ProductId> {
Attribute<Integer> totalUnits();
Attribute<Integer> availableUnits();
}
}
public static class Repository extends AggregateRepository<ProductId, Root, Root.Attributes> {
@Override
public ProductDataAccess<Root.Attributes> dataAccess() {
return (ProductDataAccess<Attributes>) super.dataAccess();
}
}
}
public interface ProductDataAccess<N extends Product.Root.Attributes>
extends EntityDataAccess<ProductId, N> {
}
public class ProductId extends StringId {
public ProductId(String id) {
super(id);
}
}
Aggregate et composants liés
Définition des requêtes utilisées par le dépôt Identifiant de l’entité racine
Définition des Commands
public interface CreateProduct extends Command {
Attribute<ProductId> productId();
}
public interface AddUnits extends Command {
Attribute<ProductId> productId();
Attribute<Integer> units();
}
Ajout d’un Listener pour la création d’un produit
public class Factory extends AggregateFactory<ProductId, Root, Root.Attributes> {
@MessageListener(processes = ProductManagement.class)
public Root buildProductWithNoStock(CreateProduct command) {
Root product = newAggregateWithId(command.productId().value());
product.attributes().totalUnits().value(0);
product.attributes().availableUnits().value(0);
return product;
}
}
Ajout d’un Listener pour l’ajout d’unités
public static class Root extends AggregateRoot<ProductId, Root.Attributes> {
@MessageListener(runner = AddUnitsRunner.class, processes = ProductManagement.class)
public void addUnits(AddUnits command) {
int units = command.units().value();
if(units <= 0) {
throw new DomainException("Cannot add negative number of units");
}
attributes().availableUnits().value(attributes().availableUnits().value() + units);
attributes().totalUnits().value(attributes().totalUnits().value() + units);
}
...
}
public class AddUnitsRunner
extends UpdateOneRunner<AddUnits, ProductId, Product.Root> {
@Override
protected ProductId aggregateId(AddUnits message) {
return message.productId().value();
}
}
Service permettant la localisation de l’Aggregate
Listener dans l’Aggregate Root
Simple mais un peu fastidieux...
▶
Chaque classe/interface est simple à implémenter
▶
… mais il y en a « beaucoup »
▶
… et on en a vite oublié une.
▶
Le principe de séparation des préoccupations est à ce prix
▶
… tout comme la séparation entre définition et
implémentation
PC fournit des outils adressant ce problème
▶
EMIL (Extended Messaging Intermediate Language), un
DSL permettant la description concise d’un processus
implémenté par PC
▶
Des outils de génération de code prenant une description
EMIL en entrée
La représentation EMIL de ProductManagement
process ProductManagement
CreateProduct? -> F{Product.Factory}[buildProductWithNoStock]
AddUnits? -> Ru{AddUnitsRunner}
@Product.Root[addUnits]
▶
Les outils de génération de code vont créer toutes les
classes et méthodes
▶
Il ne restera plus qu’à remplir le corps des méthodes
Comment implémenter le
stockage et le transport ?
PC utilise un mécanisme d’extensions
▶
Extension = un ensemble de classes implémentant certaines interfaces
▶
Deux types d’extensions
▶
Stockage
▶
Transport (des Events)
▶
Les classes fournies par les extensions aident les développeurs à
implémenter
▶
Les données concrètes (Entities et Events)
▶
Les requêtes vers une base de donnée (Storage)
▶
La publication des données liés aux Events (Messaging)
Stockage de l’Aggregate Product
@Entity
public class ProductData
implements Product.Root.Attributes, Serializable {
@Override
public Attribute<ProductId> identifier() {
return stringId(ProductId.class)
.read(() -> productId)
.write(value -> productId = value)
.build();
}
@Id
private String productId;
...
}
@DataAccessImplementation(
aggregateRoot = Product.Root.class,
dataImplementation = ProductData.class,
storageName = SpringJpaStorage.NAME
)
public class ProductJpaDataAccess
extends JpaDataAccess<ProductId, ProductData, String>
implements ProductDataAccess<ProductData> {
@Autowired
private ProductJpaRepository repository;
@Override
protected String convertId(ProductId id) {
return id.stringValue();
}
@Override
protected JpaRepository<ProductData, String> jpaRepository() {
return repository;
}
}
Implémentation des données
Implémentation des requêtes
Plusieurs extensions de stockage disponibles
▶
Mémoire (en vue de tester la logique métier)
▶
Spring Data MongoDB
▶
Spring Data JPA
Implémentation des Commands
@MessageImplementation(message = CreateProduct.class)
@SuppressWarnings("serial")
public class CreateProductData implements
Serializable, CreateProduct {
@Override
public Attribute<ProductId> productId() {
return stringId(ProductId.class)
.read(() -> productId)
.write(value -> productId = value)
.build();
}
private String productId;
}
@MessageImplementation(message = AddUnits.class)
@SuppressWarnings("serial")
public class AddUnitsData implements Serializable,
AddUnits {
...
@Override
public Attribute<Integer> units() {
return single(Integer.class)
.read(() -> units)
.write(value -> units = value)
.build();
}
private int units;
}
Plusieurs extensions de transport disponibles
▶
Mémoire (en vue de tester la logique métier)
▶
Pulsar (messages JSON)
▶
Kafka (messages JSON)
Les extensions génèrent aussi du code
▶
L’outil de génération de code peut utiliser la logique fournie
par les extensions
▶
Les classes d’implémentation du stockage et du transport
seront générées
Quelle est la structure d’une
application PC ?
Cela dépend du type d’application
▶
JavaSE
▶
Application web propulsée par Spring Boot
▶
...
Dans tous les cas, il faut définir un Module
▶
Un Module est représenté par une interface
▶
Tout composant définit dans un subpackage y est inclus
▶
Chaque composant du module doit avoir un nom unique
package poussecafe.shop;
import poussecafe.domain.Module;
/**
* Models an online shop where Customers may buy Products by placing Orders. Customers receive Messages giving them
* an update about the handling of their Orders.
*/
public interface Shop extends Module {
}
Ensuite, sélectionner les Modules à charger
public class ShopBundle {
public static BundleConfigurer configure() {
return new BundleConfigurer.Builder()
.module(Shop.class)
.build();
}
private ShopBundle() {
}
}
Ajout du module Shop dans un Bundle
Enfin, instancier le Runtime
▶
Ci-dessous, un exemple Spring Boot
▶
Définition et implémentation sont « connectés »
@Configuration
@Import(RuntimeConfiguration.class)
public class ApplicationConfiguration {
@Bean
protected Bundles bundles(
Messaging messaging,
SpringJpaStorage storage) {
MessagingAndStorage messagingAndStorage = new MessagingAndStorage(messaging, storage);
return new Bundles.Builder()
.withBundle(ShopBundle.configure()
.defineThenImplement()
.messagingAndStorage(messagingAndStorage)
.build())
.build();
}
}
PC fournit un bridge avec Spring
▶
Ce bridge permet l’injection de composants PC dans des
Bean
@PostMapping(path = "/product")
public void createProduct(@RequestBody CreateProductView input) {
ProductId productId = new ProductId(input.id);
CreateProduct command = runtime.newCommand(CreateProduct.class);
command.productId().value(productId);
runtime.submitCommand(command);
}
@Autowired
private Runtime runtime;
Injection et interaction avec le Runtime PC
Comment faciliter la
communication avec les experts ?
Le Ubiquitous Language apparaît dans le code
▶
PC favorise la définition d’éléments dont le nom est
naturellement issu du Ubiquitous Language
▶
… mais les experts lisent rarement du code
▶
… et un DSL comme EMIL reste rébarbatif
PC fournit un outil de génération de doc
▶
Le code est l’unique référence
▶
HTML ou PDF sont générés automatiquement
▶
La documentation inclut du texte et des schémas
Schéma de processusExtrait de texte
Je veux me lancer ! Quels sont
les outils à ma disposition ?
Un plug-in et un archetype Maven
▶
Génération de projet (via l’archétype)
▶
mvn archetype:generate ...
▶
Validation de code
▶
mvn pousse-cafe:validate
▶
Génération de documentation
▶
mvn pousse-cafe:generate-doc
▶
Génération de code
▶
mvn pousse-cafe:update-process -DprocessName=...
Une extension Eclipse
▶
Validation de code
▶
Liste et export des processus au format EMIL
▶
Un éditeur EMIL
Du contenu en ligne
▶
Un site web (avec un guide de référence)
https://www.pousse-cafe-framework.org/
▶
Le code source et des exemples
https://github.com/pousse-cafe
▶
Un tag sur StackOverflow
https://stackoverflow.com/questions/tagged/pousse-cafe
▶
Un compte Twitter
@PousseCafeFW
Avez-vous des questions ?
https://www.pousse-cafe-framework.org/
https://github.com/pousse-cafe
Twitter : @PousseCafeFW

More Related Content

Similar to Implémentation efficace et durable de processus métiers complexes

Esa1 g formation-utilisation-de-zmanager-unified-resource-manager-pour-serveu...
Esa1 g formation-utilisation-de-zmanager-unified-resource-manager-pour-serveu...Esa1 g formation-utilisation-de-zmanager-unified-resource-manager-pour-serveu...
Esa1 g formation-utilisation-de-zmanager-unified-resource-manager-pour-serveu...
CERTyou Formation
 
Oxalide Morning tech #2 - démarche performance
Oxalide Morning tech #2 - démarche performanceOxalide Morning tech #2 - démarche performance
Oxalide Morning tech #2 - démarche performance
Ludovic Piot
 

Similar to Implémentation efficace et durable de processus métiers complexes (20)

iTunes Stats
iTunes StatsiTunes Stats
iTunes Stats
 
Solution d'OTA
Solution d'OTASolution d'OTA
Solution d'OTA
 
Spring Boot & Containers - Do's & Don'ts
Spring Boot & Containers - Do's & Don'tsSpring Boot & Containers - Do's & Don'ts
Spring Boot & Containers - Do's & Don'ts
 
Analyse et optimisation des performances du moteur SQL Serveur
Analyse et optimisation des performances du moteur SQL ServeurAnalyse et optimisation des performances du moteur SQL Serveur
Analyse et optimisation des performances du moteur SQL Serveur
 
Java dans Windows Azure: l'exemple de Jonas
Java dans Windows Azure: l'exemple de JonasJava dans Windows Azure: l'exemple de Jonas
Java dans Windows Azure: l'exemple de Jonas
 
Chorégraphie distribuée à partir d’un processus d’orchestration BPMN
Chorégraphie distribuée à partir d’un processus d’orchestration BPMNChorégraphie distribuée à partir d’un processus d’orchestration BPMN
Chorégraphie distribuée à partir d’un processus d’orchestration BPMN
 
Checklist pour concevoir une application dans le cloud.10 conseils à l'attent...
Checklist pour concevoir une application dans le cloud.10 conseils à l'attent...Checklist pour concevoir une application dans le cloud.10 conseils à l'attent...
Checklist pour concevoir une application dans le cloud.10 conseils à l'attent...
 
Aspect avec AspectJ
Aspect avec AspectJAspect avec AspectJ
Aspect avec AspectJ
 
Esa1 g formation-utilisation-de-zmanager-unified-resource-manager-pour-serveu...
Esa1 g formation-utilisation-de-zmanager-unified-resource-manager-pour-serveu...Esa1 g formation-utilisation-de-zmanager-unified-resource-manager-pour-serveu...
Esa1 g formation-utilisation-de-zmanager-unified-resource-manager-pour-serveu...
 
Usine logicielle à Orange Labs
Usine logicielle à Orange LabsUsine logicielle à Orange Labs
Usine logicielle à Orange Labs
 
Tapestry
TapestryTapestry
Tapestry
 
BBL - Monitoring - kyriba
BBL - Monitoring - kyribaBBL - Monitoring - kyriba
BBL - Monitoring - kyriba
 
Machines Virtuelles dans Azure quoi de neuf ?
Machines Virtuelles dans Azure quoi de neuf ?Machines Virtuelles dans Azure quoi de neuf ?
Machines Virtuelles dans Azure quoi de neuf ?
 
Machines Virtuelles dans Azure quoi de neuf ?
Machines Virtuelles dans Azure quoi de neuf ?Machines Virtuelles dans Azure quoi de neuf ?
Machines Virtuelles dans Azure quoi de neuf ?
 
Industrialisation des développements logiciels
Industrialisation des développements logicielsIndustrialisation des développements logiciels
Industrialisation des développements logiciels
 
Les containers docker vu par un chef cuisinier et un mécanicien
Les containers docker vu par un chef cuisinier et un mécanicienLes containers docker vu par un chef cuisinier et un mécanicien
Les containers docker vu par un chef cuisinier et un mécanicien
 
Chaine de production pipeline
Chaine de production   pipelineChaine de production   pipeline
Chaine de production pipeline
 
Morning tech #2 - Démarche performance slides
Morning tech #2 - Démarche performance slidesMorning tech #2 - Démarche performance slides
Morning tech #2 - Démarche performance slides
 
Oxalide Morning tech #2 - démarche performance
Oxalide Morning tech #2 - démarche performanceOxalide Morning tech #2 - démarche performance
Oxalide Morning tech #2 - démarche performance
 
L'Agilité en 4D - Christophe Battu
L'Agilité en 4D - Christophe BattuL'Agilité en 4D - Christophe Battu
L'Agilité en 4D - Christophe Battu
 

More from Geeks Anonymes

More from Geeks Anonymes (20)

Programmer sous Unreal Engine
Programmer sous Unreal EngineProgrammer sous Unreal Engine
Programmer sous Unreal Engine
 
Managing Open Source Licenses (Geeks Anonymes)
Managing Open Source Licenses (Geeks Anonymes)Managing Open Source Licenses (Geeks Anonymes)
Managing Open Source Licenses (Geeks Anonymes)
 
Reprendre le contrôle de ses données
Reprendre le contrôle de ses donnéesReprendre le contrôle de ses données
Reprendre le contrôle de ses données
 
Geeks Anonymes - Le langage Go
Geeks Anonymes - Le langage GoGeeks Anonymes - Le langage Go
Geeks Anonymes - Le langage Go
 
Le rôle du testeur et le Blackbox testing
Le rôle du testeur et le Blackbox testingLe rôle du testeur et le Blackbox testing
Le rôle du testeur et le Blackbox testing
 
Kubernetes
KubernetesKubernetes
Kubernetes
 
Vulnérabilités au cœur des applications Web, menaces et contre-mesures
 Vulnérabilités au cœur des applications Web, menaces et contre-mesures Vulnérabilités au cœur des applications Web, menaces et contre-mesures
Vulnérabilités au cœur des applications Web, menaces et contre-mesures
 
191121 philippe teuwen cryptographie et attaques materielles
191121 philippe teuwen cryptographie et attaques materielles191121 philippe teuwen cryptographie et attaques materielles
191121 philippe teuwen cryptographie et attaques materielles
 
"Surfez couverts !" - Conseils de Cyber securité
"Surfez couverts !" - Conseils de Cyber securité "Surfez couverts !" - Conseils de Cyber securité
"Surfez couverts !" - Conseils de Cyber securité
 
Introduction au développement mobile - développer une application iOS et Andr...
Introduction au développement mobile - développer une application iOS et Andr...Introduction au développement mobile - développer une application iOS et Andr...
Introduction au développement mobile - développer une application iOS et Andr...
 
Le langage rust
Le langage rustLe langage rust
Le langage rust
 
Test your code
Test your codeTest your code
Test your code
 
Intelligence artificielle et propriété intellectuelle
Intelligence artificielle et propriété intellectuelleIntelligence artificielle et propriété intellectuelle
Intelligence artificielle et propriété intellectuelle
 
Pour une histoire plophonique du jeu video
Pour une histoire plophonique du jeu videoPour une histoire plophonique du jeu video
Pour une histoire plophonique du jeu video
 
Become Rick and famous, thanks to Open Source
Become Rick and famous, thanks to Open SourceBecome Rick and famous, thanks to Open Source
Become Rick and famous, thanks to Open Source
 
Reconnaissance vocale et création artistique
Reconnaissance vocale et création artistiqueReconnaissance vocale et création artistique
Reconnaissance vocale et création artistique
 
Natural Language Processing
Natural Language ProcessingNatural Language Processing
Natural Language Processing
 
Sécurité, GDPR : vos données ont de la valeur
Sécurité, GDPR : vos données ont de la valeur Sécurité, GDPR : vos données ont de la valeur
Sécurité, GDPR : vos données ont de la valeur
 
Modern sql
Modern sqlModern sql
Modern sql
 
Qt
QtQt
Qt
 

Implémentation efficace et durable de processus métiers complexes

  • 1. Implémentation efficace et durable de processus métiers complexes Gérard Dethier 15 janvier 2021 / Geeks Anonymes Liège https://www.gerarddethier.be
  • 2. Résumé de l’épisode précédent... https://www.youtube.com/watch?v=OmrtGo68E6M
  • 3. Tout est processus... ▶ La majorité des systèmes IT implémentent des processus métier ▶ L’implémentation implique le stockage d’un état (les données) ▶ L’état évolue par réaction à des stimuli (des commandes soumises par les utilisateurs)
  • 4. Une exécution efficace est importante ▶ L’exécution d’un grand nombre de transactions par unité de temps est parfois nécessaire ▶ Ces transactions peuvent devoir être exécutées en parallèle ▶ « Time is money »
  • 5. La maintenabilité est essentielle ▶ Les conditions évoluent ▶ Besoins (métier) ▶ Attentes (utilisateurs) ▶ Équipes (composition)
  • 6. Le Domain-Driven Design apporte des outils ▶ Domain-Driven Design = DDD ▶ Un langage commun entre développeurs et experts du domaine ▶ Le code est un modèle de la réalité du terrain ▶ Des règles de conception favorisant ▶ maintenabilité ▶ efficacité ▶ robustesse
  • 7. DDD dans une coquille de noix
  • 8. DDD est une méthodologie de modélisation ▶ Développeurs et experts coconstruisent un modèle abstrait ▶ DDD fournit des composants de base ▶ Ils utilisent un langage commun ▶ Le Ubiquitous Language ▶ Le modèle est descriptible à l’aide de code
  • 9. Les composants ont différentes caractéristiques ▶ État ▶ Représentation des données ▶ Les données sont immuables ou non ▶ Maintient des contraintes liées aux données ▶ Comportement ▶ Opérations pouvant impliquer l’état ▶ Structure ▶ Regroupement d’autre composants ▶ Stratégie ▶ Possibilité de raisonner sur des systèmes « morcelés » et à grande échelle
  • 10. Les composants avec un état ▶ Value Object (VO) ▶ Données immuable ▶ Le comportement n’altère pas l’état ▶ Entity ▶ Données non-immuables ▶ Le comportement peut altérer l’état ▶ Domain event (ou event) ▶ Permet le transport de données ▶ Pas de comportement
  • 11. Aggregate et composants liés ▶ Aggregate ▶ Graphe d’Entities et VOs liés par un ensemble de contraintes fortes ▶ Accès uniquement via l’Aggregate Root (= Entity garantissant le respect des contraintes) ▶ Factory ▶ Produit des Aggregates ▶ Les contraintes sont respectées initialement ▶ Repository ▶ Stocke et récupère des Aggregates ▶ Les contraintes sont respectées au moment du stockage et lors de la récupération
  • 12. Le Module ▶ Composant structurant ▶ Définit un espace de nommage pour ▶ Aggregates ▶ Entities ▶ VOs
  • 13. Autres composants ▶ Service ▶ Pas d’état ▶ Comportement qui ne peut être mis ailleurs ▶ Bounded Context ▶ Stratégie ▶ Partition d’un système ▶ Peut contenir un ou plusieurs Modules, voir des fragments ▶ Context Map ▶ Graphe liant les Bounded Contexts ▶ Lien = dépendance (librairies), transport de données (event ou autre)
  • 14. Quelques règles de conception... ▶ Un seul Aggregate mis à jour par transaction ▶ Les règles de consistance portant sur plusieurs Aggregates sont implémentées à l’aide Events ▶ Les Aggregates doivent être les plus petits possibles ▶ Le code documente le modèle implémenté ▶ Conventions de nommage ▶ Utilisation du Ubiquitous Language
  • 15. Appliquer DDD n’est pas toujours simple ▶ Bonne connaissance théorique requise ▶ Trop abstrait pour les experts métier ▶ Pas assez concret pour les développeurs ▶ Implique la résolution de difficultés techniques ▶ Séparation claire entre modèle et détails techniques ▶ Dans un contexte distribué, transport et traitement des événements
  • 16. Un petit « pousse » pour digérer tout cela ?
  • 17. Pousse-Café (PC) est un framework... ▶ Java (11+) ▶ Libre et open-source (Apache 2.0) ▶ Léger ▶ Modulaire ▶ Facilitant... ▶ l’implémentation efficace de processus complexes ▶ l’abstraction du stockage et du transport des données ▶ une bonne communication entre développeurs et experts métier
  • 18. PC interprète le DDD dans l’« univers » Java ▶ Classes ▶ VOs ▶ Entities ▶ Factories ▶ Repositories ▶ Services ▶ Aggregates ▶ Interfaces ▶ Events ▶ Modules
  • 19. PC introduit quelques éléments supplémentaires ▶ Les Commands ▶ Requêtes soumises par les utilisateurs ▶ Définies par une classe ou une interface ▶ Les Processes ▶ Interfaces nommant et décrivant des processus métiers ▶ Les Listeners ▶ Méthodes traitant Event ou Command ▶ Liés à un ou plusieurs Processes
  • 20. PC fournit un Runtime ▶ Charge un ensemble défini de composants au démarrage ▶ Reçoit des Commands ▶ Consomme les Events à partir d’un bus de communication ▶ Pour chaque Command/Event traité ▶ détermine le(s) Aggregates à créer/mettre à jour/supprimer ▶ exécute les Listeners des Aggregate Roots, Factories et Repositories ▶ sauvegarde les changements et publie les Events potentiellement émis
  • 21. Comment décrit-on un processus métier avec PC ?
  • 22. Il y a quelques étapes... ▶ Définir le Process ▶ Définir les Aggregates ▶ Aggregate Roots ▶ Factories ▶ Repositories ▶ Définir les Commands et Events ▶ Créer les Listeners et les lier au Process
  • 23. Exemple : ProductManagement ▶ Domaine : plateforme de e-commerce ▶ Portée ▶ Création d’un produit sans stock ▶ Ajout d’unités au stock ▶ État ▶ Un Aggregate → Product
  • 24. Définition du Process ProductManagement public interface ProductManagement extends Process { }
  • 25. Définition de l’Aggregate Product @Aggregate public class Product { public static class Factory extends AggregateFactory<ProductId, Root, Root.Attributes> { } public static class Root extends AggregateRoot<ProductId, Root.Attributes> { public static interface Attributes extends EntityAttributes<ProductId> { Attribute<Integer> totalUnits(); Attribute<Integer> availableUnits(); } } public static class Repository extends AggregateRepository<ProductId, Root, Root.Attributes> { @Override public ProductDataAccess<Root.Attributes> dataAccess() { return (ProductDataAccess<Attributes>) super.dataAccess(); } } } public interface ProductDataAccess<N extends Product.Root.Attributes> extends EntityDataAccess<ProductId, N> { } public class ProductId extends StringId { public ProductId(String id) { super(id); } } Aggregate et composants liés Définition des requêtes utilisées par le dépôt Identifiant de l’entité racine
  • 26. Définition des Commands public interface CreateProduct extends Command { Attribute<ProductId> productId(); } public interface AddUnits extends Command { Attribute<ProductId> productId(); Attribute<Integer> units(); }
  • 27. Ajout d’un Listener pour la création d’un produit public class Factory extends AggregateFactory<ProductId, Root, Root.Attributes> { @MessageListener(processes = ProductManagement.class) public Root buildProductWithNoStock(CreateProduct command) { Root product = newAggregateWithId(command.productId().value()); product.attributes().totalUnits().value(0); product.attributes().availableUnits().value(0); return product; } }
  • 28. Ajout d’un Listener pour l’ajout d’unités public static class Root extends AggregateRoot<ProductId, Root.Attributes> { @MessageListener(runner = AddUnitsRunner.class, processes = ProductManagement.class) public void addUnits(AddUnits command) { int units = command.units().value(); if(units <= 0) { throw new DomainException("Cannot add negative number of units"); } attributes().availableUnits().value(attributes().availableUnits().value() + units); attributes().totalUnits().value(attributes().totalUnits().value() + units); } ... } public class AddUnitsRunner extends UpdateOneRunner<AddUnits, ProductId, Product.Root> { @Override protected ProductId aggregateId(AddUnits message) { return message.productId().value(); } } Service permettant la localisation de l’Aggregate Listener dans l’Aggregate Root
  • 29. Simple mais un peu fastidieux... ▶ Chaque classe/interface est simple à implémenter ▶ … mais il y en a « beaucoup » ▶ … et on en a vite oublié une. ▶ Le principe de séparation des préoccupations est à ce prix ▶ … tout comme la séparation entre définition et implémentation
  • 30. PC fournit des outils adressant ce problème ▶ EMIL (Extended Messaging Intermediate Language), un DSL permettant la description concise d’un processus implémenté par PC ▶ Des outils de génération de code prenant une description EMIL en entrée
  • 31. La représentation EMIL de ProductManagement process ProductManagement CreateProduct? -> F{Product.Factory}[buildProductWithNoStock] AddUnits? -> Ru{AddUnitsRunner} @Product.Root[addUnits] ▶ Les outils de génération de code vont créer toutes les classes et méthodes ▶ Il ne restera plus qu’à remplir le corps des méthodes
  • 32. Comment implémenter le stockage et le transport ?
  • 33. PC utilise un mécanisme d’extensions ▶ Extension = un ensemble de classes implémentant certaines interfaces ▶ Deux types d’extensions ▶ Stockage ▶ Transport (des Events) ▶ Les classes fournies par les extensions aident les développeurs à implémenter ▶ Les données concrètes (Entities et Events) ▶ Les requêtes vers une base de donnée (Storage) ▶ La publication des données liés aux Events (Messaging)
  • 34. Stockage de l’Aggregate Product @Entity public class ProductData implements Product.Root.Attributes, Serializable { @Override public Attribute<ProductId> identifier() { return stringId(ProductId.class) .read(() -> productId) .write(value -> productId = value) .build(); } @Id private String productId; ... } @DataAccessImplementation( aggregateRoot = Product.Root.class, dataImplementation = ProductData.class, storageName = SpringJpaStorage.NAME ) public class ProductJpaDataAccess extends JpaDataAccess<ProductId, ProductData, String> implements ProductDataAccess<ProductData> { @Autowired private ProductJpaRepository repository; @Override protected String convertId(ProductId id) { return id.stringValue(); } @Override protected JpaRepository<ProductData, String> jpaRepository() { return repository; } } Implémentation des données Implémentation des requêtes
  • 35. Plusieurs extensions de stockage disponibles ▶ Mémoire (en vue de tester la logique métier) ▶ Spring Data MongoDB ▶ Spring Data JPA
  • 36. Implémentation des Commands @MessageImplementation(message = CreateProduct.class) @SuppressWarnings("serial") public class CreateProductData implements Serializable, CreateProduct { @Override public Attribute<ProductId> productId() { return stringId(ProductId.class) .read(() -> productId) .write(value -> productId = value) .build(); } private String productId; } @MessageImplementation(message = AddUnits.class) @SuppressWarnings("serial") public class AddUnitsData implements Serializable, AddUnits { ... @Override public Attribute<Integer> units() { return single(Integer.class) .read(() -> units) .write(value -> units = value) .build(); } private int units; }
  • 37. Plusieurs extensions de transport disponibles ▶ Mémoire (en vue de tester la logique métier) ▶ Pulsar (messages JSON) ▶ Kafka (messages JSON)
  • 38. Les extensions génèrent aussi du code ▶ L’outil de génération de code peut utiliser la logique fournie par les extensions ▶ Les classes d’implémentation du stockage et du transport seront générées
  • 39. Quelle est la structure d’une application PC ?
  • 40. Cela dépend du type d’application ▶ JavaSE ▶ Application web propulsée par Spring Boot ▶ ...
  • 41. Dans tous les cas, il faut définir un Module ▶ Un Module est représenté par une interface ▶ Tout composant définit dans un subpackage y est inclus ▶ Chaque composant du module doit avoir un nom unique package poussecafe.shop; import poussecafe.domain.Module; /** * Models an online shop where Customers may buy Products by placing Orders. Customers receive Messages giving them * an update about the handling of their Orders. */ public interface Shop extends Module { }
  • 42. Ensuite, sélectionner les Modules à charger public class ShopBundle { public static BundleConfigurer configure() { return new BundleConfigurer.Builder() .module(Shop.class) .build(); } private ShopBundle() { } } Ajout du module Shop dans un Bundle
  • 43. Enfin, instancier le Runtime ▶ Ci-dessous, un exemple Spring Boot ▶ Définition et implémentation sont « connectés » @Configuration @Import(RuntimeConfiguration.class) public class ApplicationConfiguration { @Bean protected Bundles bundles( Messaging messaging, SpringJpaStorage storage) { MessagingAndStorage messagingAndStorage = new MessagingAndStorage(messaging, storage); return new Bundles.Builder() .withBundle(ShopBundle.configure() .defineThenImplement() .messagingAndStorage(messagingAndStorage) .build()) .build(); } }
  • 44. PC fournit un bridge avec Spring ▶ Ce bridge permet l’injection de composants PC dans des Bean @PostMapping(path = "/product") public void createProduct(@RequestBody CreateProductView input) { ProductId productId = new ProductId(input.id); CreateProduct command = runtime.newCommand(CreateProduct.class); command.productId().value(productId); runtime.submitCommand(command); } @Autowired private Runtime runtime; Injection et interaction avec le Runtime PC
  • 45. Comment faciliter la communication avec les experts ?
  • 46. Le Ubiquitous Language apparaît dans le code ▶ PC favorise la définition d’éléments dont le nom est naturellement issu du Ubiquitous Language ▶ … mais les experts lisent rarement du code ▶ … et un DSL comme EMIL reste rébarbatif
  • 47. PC fournit un outil de génération de doc ▶ Le code est l’unique référence ▶ HTML ou PDF sont générés automatiquement ▶ La documentation inclut du texte et des schémas Schéma de processusExtrait de texte
  • 48. Je veux me lancer ! Quels sont les outils à ma disposition ?
  • 49. Un plug-in et un archetype Maven ▶ Génération de projet (via l’archétype) ▶ mvn archetype:generate ... ▶ Validation de code ▶ mvn pousse-cafe:validate ▶ Génération de documentation ▶ mvn pousse-cafe:generate-doc ▶ Génération de code ▶ mvn pousse-cafe:update-process -DprocessName=...
  • 50. Une extension Eclipse ▶ Validation de code ▶ Liste et export des processus au format EMIL ▶ Un éditeur EMIL
  • 51. Du contenu en ligne ▶ Un site web (avec un guide de référence) https://www.pousse-cafe-framework.org/ ▶ Le code source et des exemples https://github.com/pousse-cafe ▶ Un tag sur StackOverflow https://stackoverflow.com/questions/tagged/pousse-cafe ▶ Un compte Twitter @PousseCafeFW