Atomicité du code #1

Un exemple de code que j’ai simplifié ce matin :


if(validator !== null){
if(text !== "" && text.toString().match(validator.regExp) !== null)
{
hasError = false;
checkedIcon.visible = true;
}
else if(text !== "" && text.toString().match(validator.regExp) === null){
hasError = true;
checkedIcon.visible = false;
}

}
else{
console.log("TextFiledValidated : this component needs a validator,
you can set the validator using validator property")
console.trace()
throw "property exception"
}

 

sitôt remplacé par loe bloc suivant :


if (text !== ""){
hasError = (text.toString().match(validator.regExp) === null);
checkedIcon.visible = ! hasError;
}

On économise des lignes de code, de la redondance dans l’expression et on facilite la lecture.

Publicités

Controllers et services

[toc]

J’ai entendu assez souvent :

Question :
« quand je suis sur un projet MVC server-side, le code du traitement je le met où? »
Réponse :
‘ben dans le controller »

Attention : c’est une très mauvaise pratique !

Et je ne veux pas entendre : « ba tu le met où tu veux le code, de toutes facon ca marchera »

Alors mieux que ca j’ai envie de vous expliquer pourquoi vous utilisez très mal le Controller.
Ce que nous autres vieux de plus de 30 ans qualifions d’ « usage galvaudé » d’un Controller.

Un Controlleur en vrai ça fait quoi ?

Un Controlleur a un rôle assez simple : il est une chaîne dans un workflow métier ni plus ni moins.
D’ailleurs il ne fait pas partie réellement de la couche métier. Il fait partie de la couche applicative.
Il orchestre les actions métiers à réaliser. qui elles sont encapsulées dans des services métier. Bref.

Reprenons le schema classique d’un process MVC.
1/ requête HTTP
2/ Front Controller
3/ Routage
4/ Invocation d’une méthode d’un Controller
5/ Retour d’information HTTP

Nous sommes bien d’accord qu’en gros, quand le client demande « la liste des ville de la région Aquitaine », le Controlleur a pour seule mission de les lui renvoyer (en JSON, HTML, XML…)

Nous sommes bien toujours bien d’accord que techniquement, son job à lui c’est bien de les renvoyer, PAS de faire les actions métiers qui consistent à chercher les infos en base, les filtrer, ordonner, etc…

Alors on le met où en vrai le traitement « métier » ?

Le Controlleur c’est un peu comme le chef de projet : il prend une demande client, détermine la TodoList des choses à faire en interne et fait appel pour cela à différents experts métier, chacun compétent dans sa spécialité, pour obtenir le résultat attendu.
Le Controller est donc un dispatcher  : il délègue le travail aux expert des domaines concernés.
Et c’est là qu’apparaissent les Services. Les experts métier ce sont eux !

Le service

C’est le Service qui encapsule la logique métier. C’est là dedans qu’il faut « mettre le code ».
Charge au développeur de savoir bien répartir le fameux code à exécuter.
Chaque service propose des actions qu’il est capable de réaliser dans son périmètre de compétences.
Ce n’est surtout pas un épicier qui fait un peu de tout : son rôle doit être clairement identifié et délimité.
Vous savez, le fameux S de SOLID : Single Responsibility

Un exemple parlant

Prenons un exemple très simple qui en réalité fait appel à un bon paquet de traitements métier : publier un article avec WordPress.

Ca signifie quoi concrètement « publier » ? ça sous-entend quoi ?
et bien il s’agit d’un véritable workflow à lui tout seul.
Ne soyons pas peureux, listons les :

1/ vérifier les données pour l’intégrité en base
–> Service sollicité : validation et échappement des données POST

2/ enregistrer les données en base et changer l’état du billet
–> Services sollicité : ORM

3/ générer l’URL publique
Service sollicité : générateur d’URL, URL-rewriting, URL-shortener

4/ Regénérer le sitemap pour le SEO Google
Service sollicité : générateur de sitemap XML

5/ publier la news sur Twitter, Facebook
Services sollcités : publishing sur réseaux sociaux

6/ Avertir les abonnés du site WordPress
internautes abonnés, pingback
Service sollcité : gestionnaire de Pingback

Ca en fait un paquet de service ! Et chacun a un rôle bien particulier.
On comprend alors très vite que si on mettait dans le Controller tout le code
nécessaire pour réaliser ces 6 opérations, ca serait ingérable. Il y aurait du code dans tous les sens.
On serait capable de développer, mais bien vite incapables de maintenir et de fair évoluer l’application.


Et pour peu qu’on ait besoide faire appel à une ou plusieurs de ces 6 étapes dans un contexte complètement différent, on serait obligé de faire des infâmes copier/coller, créer des conditions pour quel tel bout de code soit éxécuté ou pas.
N’oublions pas qu’un service n’a jamais (ou le moins possible) à savoir dans quel contexte il est appelé.
Ou dit autrement, le contexte d’usage ne doit pas conditionner le comportement du service.

Les conditions doivent être gérées par le controlleur. J’appelle ou j’appelle pas tel service, mais si je l’appelle je suis conscient qu’il fera toujours le même job.

Les avantages d’un service :

Les (nombreux) avantages d’un Service :

  • c’est lui qui contient le code métier (en partie)
  • on lui dit ce qu’il doit faire, pas comment le faire
  • il a une responsabilité limitée : il fait un nombre limité de choses mais les fait bien.
  • il est constant, ne se comporte pas de facon conditionnelle au contexte d’appel
  • il est utilisable partout où c’est nécessaire, invocable depuis n’importe quel Controller.
  • son implémentation est centralisée : si on veut le modifier (code, règle, librairie) tout est dedans et nulle part ailleurs. Pas besoin de propagation.
  • pas besoin de l’instancier : c’est le container de services du framework qui gère. Dès qu’on en a besoin, ya qu’à se servir.
    Merci au Lazy Loading et à la Dependency Injection (du framework) qui nous décharge de sa gestion
  • Un service est par nature instancié en tant que Singleton. Laissez le framework gérer ce pattern, il le fait mieux que vous !

A quoi sert le pattern Factory (fabrique)

Le pattern Factory sert avant tout à abstraire les mécanisme d’instanciation d’une classe.
Elle permet de s’afranchir de la manière et du contexte dans lequel un objet est créé.

Comme j’aime bien expliquer des concepts par des exemple, plutôt que par un long discours ou des schema de génie logiciel UML, et bien voici 2 exemples qui me semblent très parlant.

Le restaurant

Imaginez, vous êtes serveur dans un restaurant-snack.
Votre job consiste à prendre les commandes à la table du client, envoyer les ordres de commande à la cuisine, récupérer les plats et les amener à table.
Je simplifie volontairement mais votre processus s’arrête ici.

C’est votre coeur de métier de savoir gérer votre salle :
– quelle table a été servie ou pas
– si les clients ont besoin d’une nouvelle carafe d’eau
– pourquoi le client a pris tel plat ou tel autre
– informer un client si un plat n’est pas disponible

…mais le cuisinier ne doit pas s’en soucier, car ce n’est pas son job.
A l’inverse, c’est le coeur de métier du cuisine de savoir gérer sa cuisine :

  • gérer son temps pendant le rush
  • gérer ses stocks et approvisionnements
  • organiser la chaîne de préparation des plats
  • comment préparer un sandwich froid ou un panini au fromage

…mais vous ne devez pas vous en soucier car ce n’est pas votre job.

Voila, à chacun son job. Chaque métier doit savoir abstraire son travail pour pouvoir communiquer avec les autres.

C’est ici qu’intervient la fabrique !

L’habillage (wearset)