<style>
.reveal {
font-family: Roboto, Source Sans Pro, Helvetica, sans-serif;
font-size: 42px;
font-weight: 300;
}
.reveal h1,
.reveal h2,
.reveal h3,
.reveal h4,
.reveal h5,
.reveal h6 {
margin: 0 0 20px 0;
font-family: Roboto, Source Sans Pro, Helvetica, sans-serif;
font-weight: 500;
line-height: 1.2;
letter-spacing: normal;
text-transform: uppercase;
text-shadow: none;
word-wrap: break-word;
}
.reveal section img {
margin: initial !important;
background: initial !important;
border: initial !important;
box-shadow: initial !important;
}
</style>
# Fonctions<br/> & <br/>inversion de dépendance
---
### SOLID Principles
---
#### D
Dependency Inversion Principle
=
Principe d'inversion de dépendance
---
*Les implémentations de haut niveau, qui représentent des règles métier complexes ne devraient pas être affectées par des changements dans les implémentations de bas niveau qui représentent des détails techniques.*
---
Si je change de base de donnée
<small>*implémentation technique de bas niveau*</small>
Je ne devrais pas avoir à modifier le code qui permet d'enregistrer un nouveau CNFS candidat
<small>*implémentation métier de haut niveau*</small>
---
<img src="https://i.ibb.co/hDnVXp9/D-principe.jpg">
---
#### La solution proposée
---
Faire en sorte que les implémentations techniques de bas niveau soient représentées par des interfaces.
---
Ainsi les implémentations métier de haut niveau dépendent des interfaces qui représentent les implémentations techniques de bas niveau et non leurs implémentations concrètes.
---
#### C'est très bien
Cette solution communément admise est tout à fait valide dans un contexte de programmation orientée objet.
---
#### Mais...
Bien que JavaScript soit un langage multi-paradigmes qui fonctionne en orienté objet, ce n'est pas le mode qui a été choisi dans Conseiller Numérique.
---
### Quels principes issus de la programmation fonctionnelle peuvent nous aider ?
---
- Fermetures (Closures)
- Fonctions d'ordre supérieur
- Curryfication
---
### Fermetures
---
Une fermeture est une fonction qui a accès au contexte d'appel.
---
```javascript
const contexte = 'contexte défini en dehors de la fonction.';
const fermeture = () => {
console.log(`J'ai accès au ${contexte}`);
};
fermeture();
```
```
> J'ai accès au contexte défini en dehors de la fonction.
```
---
### Fonctions d'ordre supérieur
---
Soit au moins une fonction en argument :
```javascript
let numbers = [4, 2, 5, 1, 3];
numbers.sort((a, b) => a - b);
console.log(numbers);
```
```
> Array [1, 2, 3, 4, 5]
```
---
Soit retourne une fonction comme résultat :
```javascript
const ordreCroissant = (a, b) => a - b;
const ordreDecroissant = (a, b) => b - a;
const ordre = croissant => croissant
? ordreCroissant
: ordreDecroissant;
let numbers = [4, 2, 5, 1, 3];
let valeurBoutonTri = true;
numbers.sort(ordre(valeurBoutonTri));
console.log(numbers);
valeurBoutonTri = false;
numbers.sort(ordre(valeurBoutonTri));
console.log(numbers);
```
```
> Array [1, 2, 3, 4, 5]
> Array [5, 4, 3, 2, 1]
```
---
### Curryfication
---
<img src="https://upload.wikimedia.org/wikipedia/commons/8/86/HaskellBCurry.jpg">
Haskell Brooks Curry
Logicien et mathématicien américain.
Ses travaux ont posé les bases de la programmation fonctionnelle
---
Transformation d'une fonction à plusieurs arguments en une fonction à un argument qui retourne une fonction
---
```javascript
const uncurriedAdd = (x, y) => x + y;
const uncurriedAddResult = uncurriedAdd(4, 3);
console.log(uncurriedAddResult)
const curriedAdd = x => y => x + y;
const curriedAddResult = curriedAdd(4)(3);
console.log(curriedAddResult)
```
```
> 7
> 7
```
---
### Et quand on combine les trois
---
On peut utiliser la curryfication pour séparer les paramètres d'une fonction en plusieurs groupes.
---
Par exemple
- un groupe pour les paramètres liés aux détails techniques
- un autre groupe pour les paramètres liés au métier.
```javascript
const getConseillersSansCurry = async (db, id, statut) =>
await ...
const getConseillers = db => async (id, statut) =>
await ...
```
---
Le principe de fermeture nous permet d'accéder aux paramètres techniques dans la fonction qui reçoit les paramètres métier.
```javascript
const getConseillers = db => async (id, statut) =>
await db
.collection('conseillers')
.findOne({ _id: id, statut: statut });
```
---
La fonction devient alors une fonction d'ordre supérieur dont les paramètres sont liés aux détails techniques et qu'on évitera d'utiliser dans le code métier.
```javascript
// Code non métier : préparation technique.
const db = await app.get('mongoClient');
const getConseillersMetier = getConseillers(db);
codeMetier(id, statut, getConseillersMetier);
```
---
Cette fonction retourne une fonction dont les paramètres sont exclusivement liés au métier, on peut ainsi l'utiliser sans risque de changement si l'implementation technique évolue.
```javascript
// Code métier : impossible de savoir si mongo est utilisé.
const conseillersRecrutes =
await getConseillersMetier(id, 'RECRUTE');
```
---
Pour le nommage plutôt que `getConseillers` on peut utiliser `getConseillersRepository`.
---
Le terme `Repository` représente un dépôt où l'on stocke et récupère des données, il peut avoir plusieurs impémentations : *mongo*, *postgres*, *système de fichier*, *api externe*, et ... autant que l'on veut dans nos tests avec des stubs ou des fakes !
---
Le nom `getConseillers` étant maintenant libre on peut l'utiliser à la place de `getConseillersMetier` qui n'était pas idéal.
---
Merci de votre attention :)
{"metaMigratedAt":"2023-06-16T14:44:30.917Z","metaMigratedFrom":"YAML","title":"Fonctions & inversion de dépendance","breaks":true,"slideOptions":"{\"transition\":\"slide\",\"controls\":false,\"progress\":true,\"slideNumber\":false}","contributors":"[{\"id\":\"01d6a5d9-edd0-4d27-b734-061799130618\",\"add\":8956,\"del\":2984},{\"id\":\"5d87520c-c463-4068-a514-5e0d85b2a660\",\"add\":1,\"del\":2}]"}