Version 1 : Par module
Version 2 : Par couche
Version 3 : Par fonction
Version 4 : Par acteur
L'étape précédente permet de concevoir d'un point de vue fonctionnel le problème, mais comment peut-on le développer ?
La conception se concentrera ici sur l'organisation des acteurs
Version 1 : Par les fonctions
Version 1 : Par les fonctions
Version 2 : Par les services
Version 2 : Par les services
Version 3 : Par les données
Version 3 : Par les données
Avis personnel : Conception recommandée pour débuter
Le mieux, c'est de mixer
le tout selon les besoins
// How this code is usually written with classic services?
class documentService {
create(document) {
// persist document
}
update(id, newDocument) {
const document = this._find(id);
if (!document.isValidating && !document.isBroadcasted) {
// persist newDocument
}
}
validate(id) {
const document = this._find(id);
if (!document.isValidating && !document.isBroadcasted) {
document.isValidating = true;
// persist document
}
}
accept(id) {
const document = this._find(id);
if (document.isValidating && !document.isBroadcasted) {
document.isBroadcasted = true;
// persist
}
}
refuse(id) {
const document = this._find(id);
if (document.isValidating && !document.isBroadcasted) {
document.isValidating = false;
// persist
}
}
read(id) {
const document = this._find(id);
if (document.isBroadcasted) {
return document;
}
}
delete(id) {
const document = this._find(id);
if (document.isBroadcasted) {
// remove document
}
}
_find(id) {/*…*/}
}
// How this code should be written?
// Use of my personal FSM library (https://github.com/kneelnrise/fms-js)
function getFSM(id) {
const fsm = k.fsm.create((fsm) => {
fsm.when("draft", (state) => {
state.on("update", (data, newDocument) => {
return ["draft", newDocument];
});
state.on("validate", (data) => {
return ["validating", data];
});
});
fsm.when("validating", (state) => {
state.on("accept", (data) => {
return ["broadcast", data];
});
state.on("refuse", (data) => {
return ["draft", data];
});
});
fsm.when("broadcast", (state) => {
state.on("read", (data) => {
return ["broadcast", data];
});
});
// Currently, this function does not exist in the library, but keep the logic in mind
fsm.afterEachEvent((data, state) => {
db.persist({data: data, state: state});
});
// We initialize our FSM from saved item
const saved = db.find(id);
fsm.startWith(saved.state, saved.data);
});
}
Organisation des acteurs
Messages échangés
Comment contacter l'acteur
Cas d'étude
Cas 1 : Nom de document unique
Quel serait votre code ?
Cas 1 : Nom de document unique
@Local
class DocumentService {
@PersistentContext
private EntityManager em;
public void create(Document document) {
List<Document> existing = em.createQuery(
"SELECT d FROM Document d WHERE d.name = :name",
Document.class
)
.setParameter("name", document.getName())
.getResultList();
if (existing.size() > 0) {
em.persist(document);
}
}
}
// global db
class DocumentService {
create(document) {
db.find({name: document.name}).then((existing) => {
if (!existing) {
em.persist(document);
}
});
}
}
Cas 1 : Nom de document unique
Problème :
Ce code fonctionne, mais dans le cas ou deux documents sont insérés en base en même temps ?
Le problème survient dès qu'il y a parallélisme, réparti sur un ou plusieurs serveur(s).
Cas 1 : Nom de document unique
Solution :
Ne réaliser qu'une seule opération d'insertion à la fois.
Bloquer les autres tant qu'elle n'est pas terminée.
Attention à ne pas bloquer le système !
Remarque : Cette gestion devrait être gérée par le framework ou langage, pas par le développeur
Cas 2 : Transaction longue avant la diffusion
Pour ce cas, nous pouvons avoir un SGBD avec la notion de transaction (ex: Oracle).
Cas 2 : Transaction longue avant la diffusion
Cas 2 : Transaction longue avant la diffusion
Solution :
Chaque document est un acteur : Une seule opération à la fois par document (on ne bloque qu'un document)
Correct du point de vue métier : Deux utilisateurs ne devraient pas modifier le même document à la fois
Remarque : pour la persistence, se renseigner sur la notion de « insert only » (CR).
Fait inéluctable : L'application va crasher
Comment faire pour que notre application continue de répondre, même quand elle crash ?
Solution 1 : Duplication
Solution 2 : Supervision
La supervision consiste à déléguer les cas que notre acteur ne sait pas gérer à son supérieur.
Un supérieur racine : Se doit de maintenir le système en vie !
Solution 2 : Supervision
Le modèle même est par nature distribuable !
Webographie