Terminologie - part 2
Dans un précédent article, j'évoquais un certain nombre de terminologie bon à connaître. Voici sa suite !
Dans la façon de concevoir
YAGNI
Signifiant "You Aren’t Gonna Need It", c'est une extension du KISS où en plus nous ne codons que ce qui est nécessaire.
Autrement dit, l'objectif est de ne pas avoir d'extra code qui n'est pas utilisée (et donc réduire la complexité du code) et du coup éviter d'avoir un ensemble de code mort.
Car ces derniers peuvent poser soucis. En effet, d'un point de vue refactoring, nous allons nous poser le sens de ce code mort, et savoir / investiguer s'il est vraiment mort et quel était son objectif. Bref, perdre du temps en vain.
TDD
Ici, le "Test Driven Development" est une philosophie de développement orienté test. Le principe repose sur les 6 points suivants:
- Réfléchir à la fonctionnalité
- Ecrire les tests de la fonctionnalité
- Lancer le test qui doit échoué
- Implémenter le code de la fonctionnalité
- Lancer le test qui doit réussir
- Répéter / raffiner
Le principe étant que nous réfléchissons plus à ce que nous avons besoin avant de réfléchir à comment l'implémenter (donc nous prenons plus de recules). Mais de plus, nous évitons du code mort car nous ne codons que ce que nous avons besoin (le TDD peut être vu comme une solution pour le YAGNI). Et cela nous force aussi à produire un code très fonctionnel
En pratique même, nous faisons les étapes suivantes
Nous regardons si la méthode existe
describe('and the method "createCommitLabel" ', function () { it('should exist', function () { expect(GitUtils.createCommitLabel).to.exist; }); });
Nous déclarons la méthode et regardons si le test passe. Ensuite nous raffinons en ajoutant un critère fonctionnel:
describe('and the method "createCommitLabel" ', function () {
it('should exist', function () {
expect(GitUtils.createCommitLabel).to.exist;
});
it('should return a default value if no label set', function () {
expect(GitUtils.createCommitLabel('1.2.3')).equals('Release version: 1.2.3');
});
});
Nous faisons alors du refactoring de la méthode jusqu'à que les tests déclarés passent, et ainsi de suite:
describe('and the method "createCommitLabel" ', function () {
it('should exist', function () {
expect(GitUtils.createCommitLabel).to.exist;
});
it('should return a default value if no label set', function () {
expect(GitUtils.createCommitLabel('1.2.3')).equals('Release version: 1.2.3');
});
it('should inject the package version if a label is set', function () {
expect(GitUtils.createCommitLabel('1.2.3', 'Release: %s')).equals('Release: 1.2.3');
});
});
SOC
Le "Separation of Concerns" rejoint le "Single Responsibility Principle" du SOLID où nos fonctions, classes ont une seule responsabilité / rôle / comportement.
Autrement dit, un service par exemple ne doit gérer que des utilisateurs, et non pas les commandes et les factures (qui auront chacun leur propre service). Ce qui en plus nous amène un regroupement fonctionnel et métier.
C'est le mantra du monde unix: "do one thing well"
Dans la programmation fonctionnelle
Idempotem
Issue du monde mathématique, ce dernier indique qu'une fonction f(x) doit toujours retourner le même résultat si nous la rappelons plusieurs fois avec les mêmes paramètres.
Exemple d'une fonction non idempotem: Math.random();
Exemple d'une fonction idempotem: Math.cos(2 * Math.PI)
Agnostique
Ici, nous indiquons que notre fonction n'est pas sujette à un contexte ou à un état de notre application.
Regardons le code suivant:
class NotAgnostic { static aNumber = 1; static sum(aValue) { return NotAgnostic.aNumber + aValue; } static willChangeTheContext() { NotAgnostic.aNumber = 5; } }
Nous voyons que la méthode "sum" dépend de la variable de class "aNumber" qui peut être changé à n'importe quel moment. Ce qui peut amener à des effets de bord non désiré.
Immutable
Le principe ici est de dire que la fonction ne modifie jamais les paramètres d'entrées. Par exemple une fonction qui doit ajouter une information dans un objet "User" devra cloner cet objet d'abord puis faire la modification et retourner l'objet cloné.
Transduction
Pour expliquer la transduction, prenant un cas concret. Soit un tableau de 1000 éléments. Nous voulons:
- Récupérer les noms
- Ne garder que ceux commençant par ‘B’
- Prendre le troisième nom
Implémentons une approche naïve:
let onlyNames = oneThousandElement.map(function (row) {
return row.name;
}); // 1000 iterations
let onlyNamesWithB = onlyNames.filter (function (name) {
return name.toLowerCase().startsWith('b');
}); // 1000
iterations
let
getThirdNameWithB = onlyNamesWithB[2]; // 1 iteration
Pour obtenir notre information, nous avons fait 2001 itérations !
Le principe de la transduction est de décrire un flux de filtrage et de transformations, qui seront exécutés pour chaque élément (si nécessaire) afin de restreindre au maximum les itérations. Ce qui donnerait en Lodash:
let getThirdNameWithB = _(oneThousandElement)
.map(row => row.name)
.filter(name => name.toLowerCase().startsWith('b'))
.get(2)
.value(); // Only needed iterations and will be execute only here
Commentaires
Enregistrer un commentaire