Mieux concevoir WordPress : plugins vs thèmes

Copyright : Jordan Whitfield

Depuis quelques mois, je travaille sur la refonte de ce blog.
Fonctionnalités et design, tout va y passer !

Pour ce faire, je me suis mise à réfléchir à comment je pourrais améliorer mon utilisation de WordPress au quotidien. En tant que développeuse, il y a plein de petites choses que j’avais pris pour habitude de faire dans le code du thème que j’utilise.

Un thème est ce qui permet à un blog WordPress de changer d’apparence et d’apporter une sensibilité autre à l’expérience utilisateur. Un thème peut de ce fait proposer certaines particularités qui lui sont propres, telles que la possibilité de changer la structure de la page d’accueil, la qualité de personnaliser les tailles des images ou le pouvoir de disposer de pages responsives ou adaptatives par exemple.

Les vraies fonctionnalités d’un blog WordPress sont plus généralement pourvues grâce à des plugins. Ce sont ces mêmes plugins qui permettent d’activer et de désactiver à tout moment une fonctionnalité sur un blog.

En faisant un rapide état des lieux de mon organisation sur WordPress, je me suis rendue compte d’une chose : au cours de ces trois, presque quatre années, à utiliser ce même template WordPress, j’ai souvent répondu à mes besoins en ajoutant des lignes de code supplémentaires à mon thème original. En bref, le code de mon thème est devenu de moins en moins dissocié de mes besoins en termes de fonctionnalités. Je m’explique.

 
Au fil du temps, j’ai ajouté des fonctionnalités à ce blog par le biais du fameux fichier functions.php de mon thème. C’était simple, rapide et efficace. Du moins… en théorie ! Je me suis rendue compte que ce blog est devenu totalement dépendant de ce thème créé en 2013 lors d’une précédente refonte. En gros, si aujourd’hui je devais changer de thème et en utiliser un plus en accord avec la dernière version à jour de WordPress, je ne pourrais pas le faire aussi rapidement que je le voudrais, juste en cliquant sur un bouton. Enfin si, je pourrais, mais alors une partie des fonctionnalités que je propose sur ce blog ne serait plus disponible.

Que certaines spécificités n’existent plus, c’est une situation plus ou normale : certains thèmes proposent la possibilité de réorganiser la page d’accueil d’un blog, et pas d’autres par exemple. Il faut accepter que chaque thème possède ses propres qualités. Là où j’apprends aujourd’hui de mes erreurs passées, c’est que j’arrive plus facilement à faire la distinction entre une fonctionnalité qui doit faire partie d’un thème WordPress et une fonctionnalité que je souhaite pouvoir conserver à jamais pour le blog, qui doit par conséquent figurer dans un plugin.

 
Pour vous illustrer mes propos, je peux vous parler des copyrights des photos utilisées sur ce blog, probablement un détail pour certains, mais une information plus qu’importante à mes yeux. Si je n’avais pas revu la manière dont j’avais pensé ces copyrights courant 2012-2013, ceux-ci ne s’afficheraient pas sans ajouter un gros – très gros – morceau de code au nouveau thème que j’utiliserai. Bien sûr, le jour où je changerai de thème, il faudra également que j’ajoute une ligne sur la page de mes articles pour les voir s’afficher, mais ce sur quoi je veux insister, est sur l’effort produit pour faciliter cette addition.

Auparavant, j’utilisais des attributs HTML data-author et data-url que j’insérais sur chacune des balises d’images de mes articles. Je parsais ensuite le contenu de chacun de mes articles pour réécrire le copyright et le lien de celui-ci dans un figcaption. Ça fonctionnait super bien… mais autant vous dire que la lecture de ce code était compliquée ! Et si j’avais envie d’inviter quelqu’un qui ne code pas à écrire sur mon blog, j’étais obligée de « finaliser » son article pour avoir les copyrights au bon endroit. C’était un travail fastidieux qui m’obligeait à être parfaitement rigoureuse sur l’écriture de chacun de mes articles.

J’ai depuis créé un petit plugin pour cette fonctionnalité qui permet par une simple fonction d’obtenir ces informations.

J’ai plein d’autres exemples qui me viennent à l’esprit. J’ai toujours proposé aux utilisateurs de ce blog la possibilité de lire un article sélectionné au hasard parmi tous les articles écrits à ce jour. Cette fonctionnalité était également pourvue dans le fameux fichier functions.php de mon thème. En clair, désactiver ce thème aurait supprimé cette fonctionnalité également. Ce n’était plus possible de continuer ainsi.

 
Alors j’ai commencé à réfléchir.
Comment aurais-je écrit mes fonctionnalités si elles devaient être pensées pour des personnes qui n’ont aucune idée de ce qu’est un attribut HTML ? Comment aurais-je fait en sorte que ces mêmes personnes puissent s’en sortir sans que j’aie à intervenir à chaque fois qu’elles écrivent un nouvel article ?

J’ai ainsi décidé d’améliorer le back-office de WordPress de façon à ce que tout soit plus facilement administrable. L’idée c’est de repenser chacune de mes fonctionnalités comme si un utilisateur non-développeur devait se retrouver à utiliser mon back-office. Ça paraît bête ainsi, mais c’est véritablement important de savoir que ce que l’on code peut être utilisé par d’autres. Probablement que même un autre développeur en aurait eu marre d’ajouter des attributs HTML là où il le faut pour que tout s’affiche comme il faut (vous me suivez encore ? :)).

Cela me permettra également d’éviter d’avoir à faire de trop grosses migrations de données à chaque fois que je souhaite changer de thème. Si tout est bien organisé au moment où je souhaite utiliser un nouveau thème, alors je n’aurais plus qu’à introduire une fonction par-ci, une autre par-là, et tout marchera de la manière la plus optimale possible.

Jasmine pour des tests en JavaScript

Copyright : Archia Oryix

Les tests unitaires sont des méthodes permettant de tester de façon unitaire des éléments d’un code source. Leur principal objectif est de vérifier le bon fonctionnement de sous-ensembles de code tels que les fonctions, les procédures, les classes, etc.. Les tests unitaires garantissent que ces éléments de base fonctionnent comme souhaité et préviennent des potentiels bugs.

Jasmine est un framework de tests open-source pour JavaScript. Il possède une syntaxe assez facile à prendre en main, finalement assez proche de RSpec pour Ruby, un framework dit Behaviour-Driven Development.

Appréhender la syntaxe de Jasmine

Une suite de tests Jasmine débute avec un appel à describe, une fonction globale de Jasmine qui prend en considération deux paramètres : une chaîne de caractères et une fonction. La chaîne de caractères représente un titre pour la suite, rappelant généralement ce qui va être testé. La fonction, quant à elle, est un bloc de code qui implémente la suite.

Les spécifications, appelées simplement specs, sont définies par l’appel de la fonction globale it de Jasmine, qui elle aussi prend en paramètre une chaîne de caractères et une fonction. La chaîne de caractères définit le test et la fonction est, à proprement parler, le test. Une spec peut contenir une à plusieurs attentes – expectations. En Jasmine, une expectation est une assertion pouvant être vraie ou fausse. Un test qui passe est un test possédant toutes ses expectations à true. Un test qui échoue possède au moins une expectation à false.

describe("My first suite", function() {
  it("contains spec with an expectation", function() {
    expect(true).toBe(true);
  });
});

Les blocs describe et it sont des fonctions. Celles-ci peuvent donc contenir tout le code nécessaire à l’exécution des tests. Les règles classiques de scope en JavaScript s’y appliquent ; ce qui signifie que toutes les variables déclarées dans un bloc describe seront disponibles dans chacun des blocs it que possède la suite.

describe("My first suite", function() {
  var a = true;

  it("contains spec with an expectation", function() {
    expect(a).toBe(true);
  });
});

Les expectations sont construites à partir de la fonction expect qui prend en argument une valeur, appelée la valeur réelle. Le tout est suivi d’une fonction dite matcher qui prend en argument la valeur attendue.

Before et After

Il est possible d’exécuter du code avant ou après chacune des specs écrites, respectivement grâce aux fonctionnalités beforeEach et afterEach. Cela peut devenir très pratique si l’on veut factoriser du code, ou si l’on utilise des variables globales que l’on soit réinitialiser après un test.

describe("My first suite with 'beforeEach' and 'afterEach'", function() {
  var a = 0;

  beforeEach(function() {
    a += 1;
  });

  afterEach(function() {
    a = 0;
  });

  it("checks the value of a", function() {
    expect(a).toEqual(1);
    a += 1;
  });

  it("expects a to still be equal to 1", function() {
    expect(a).toEqual(1);
  });
});

Il est également possible d’exécuter du code avant ou après toutes les specs contenues dans une suite. Comme le suggère son nom, la fonction beforeAll est appelée avant l’exécution de toutes les specs, et afterAll est appelée après l’exécution de toutes les specs.

describe("My first suite with 'beforeAll' and 'afterAll'", function() {
  var a;

  beforeAll(function() {
    a += 1;
  });

  afterAll(function() {
    a = 0;
  });

  it("checks the value of a", function() {
    expect(a).toEqual(1);
    a += 1;
  });

  it("does not reset a between specs", function() {
    expect(a).toEqual(2);
  });
});

Les matchers

Un matcher produit une comparaison booléenne entre la valeur réelle d’un élément et sa valeur attendue. Si ces deux valeurs sont divergentes, l’expectation est considérée comme fausse, et Jasmine fait échouer la spec.

Un matcher peut aussi être évalué avec une assertion négative. Il suffit pour cela d’ajouter le mot clé not avant l’utilisation du matcher.

describe("My first suite", function() {
  var a = true;

  it("contains spec with an expectation", function() {
    expect(a).not.toBe(false);
  });
});

Un grand nombre de matchers sont disponibles nativement dans Jasmine.

toBe

Le matcher toBe compare deux valeurs entre elles grâce à l’opérateur === en JavaScript.

describe("The 'toBe' matcher", function() {
  var a = 1,
      b = 2;

  it("compares with ===", function() {
    expect(a + b).toBe(3);
    expect(a).not.toBe(b);
  });
});

toEqual

Le matcher toEqual permet de vérifier l’équivalence de deux valeurs. toBe est donc plus strict que toEqual.

describe("The 'toEqual' matcher", function() {
  it("works with simple variables", function() {
    var a = 4;
    expect(a).toEqual(4);
  });

  it("works also well with arrays", function() {
    var b = new Array('1', '2'),
        c = new Array('1', '2');
    expect(b).toEqual(c);
  });
});

toMatch

Le matcher toMatch permet la comparaison avec les expressions régulières. Il permet de tester la bonne structure d’une valeur selon un pattern bien défini.

toMatch fonctionne également avec les chaînes de caractères, qui seront ensuite analysées comme des expressions régulières.

describe("The 'toMatch' matcher", function() {
  var message = "hello world!";

  it("compares with RegExp", function() {
    expect(message).toMatch(/^hello/);
    expect(message).toMatch("hello");
    expect(message).toMatch(/world!$/);
    expect(message).not.toMatch(/boy/);
  });
});

toBeNull

toBeNull permet de tester la nullité d’un élément. Si cet élément possède une valeur dite null, alors l’expectation sera considérée true. Le cas échéant, Jasmine fait échouer la spec.

describe("The 'toBeNull' matcher", function() {
  var a = null,
      b = "test";

  it("compares with null", function() {
    expect(a).toBeNull();
    expect(b).not.toBeNull();
  });
});

toContain

toContain permet de vérifier la présence d’un élément dans un tableau.

describe("The 'toContain' matcher", function() {
  var a = ["banana", "pineapple", "coconut"];

  it("finds an item in an Array", function() {
    expect(a).toContain("banana");
    expect(a).not.toContain("strawberry");
  });
});

toContain fonctionne également avec les chaînes de caractères : la fonction permet alors de vérifier si un ensemble de caractères figurent dans la chaîne globale.

describe("The 'toContain' matcher", function() {
  var a = "The quick brown fox jumps over the lazy dog";

  it("finds a substring in an String", function() {
    expect(a).toContain("fox");
    expect(a).not.toContain("foxy");
  });
});

toBeTruthy et toBeFalsy

Les matchers toBeTruthy et toBeFalsy permettent de tester de manière booléenne des valeurs. En JavaScript, tous types de valeurs peuvent être utilisés pour obtenir une valeur booléenne, par exemple lors de l’utilisation de la déclaration conditionnelle if.

Les valeurs suivantes seront interprétées comme étant false : undefined, null, false, 0, NaN et la chaîne de caractères vide "". Toutes les autres valeurs – objets et tableaux compris – sont considérées comme true. Les valeurs interprétées comme false sont appelées falsy, et les valeurs interprétées comme true sont appelées truthy.

Boolean(), appelé en tant que fonction, convertit son paramètre en booléen. Vous pouvez utiliser cette fonction pour savoir comment une valeur sera interprétée.

describe("The 'toBeTruthy' and 'toBeFalsy' matchers", function() {
  var a,
      b = false,
      c = 15;

  it("is for boolean casting testing", function() {
    expect(a).toBeFalsy();
    expect(a).not.toBeTruthy();
  });

  it("is for boolean casting testing", function() {
    expect(b).toBeFalsy();
    expect(b).not.toBeTruthy();
  });

  it("is for boolean casting testing", function() {
    expect(c).toBeTruthy();
    expect(c).not.toBeFalsy();
  });
});

toBeDefined et toBeUndefined

toBeDefined et toBeUndefined permettent de vérifier l’existence ou non d’une valeur. À noter une nouvelle fois que la valeur de type undefined est aussi considérée comme étant false.

En JavaScript, les variables non-initialisées ne possèdent pas de valeur, elles sont undefined. Une propriété inexistante pour un objet renvoie également une valeur dite undefined. Une fonction qui ne possède pas de return, ou une fonction possédant un return vide, est une fonction qui retourne undefined.

describe("The 'toBeDefined' and 'toBeUndefined' matchers", function() {
  var a,
      b = 3,
      c = (function() {})();

  it("compares against `defined`", function() {
    expect(a).not.toBeDefined();
    expect(b).toBeDefined();
    expect(c).not.toBeDefined();
  });

  it("compares against `undefined`", function() {
    expect(a).toBeUndefined();
    expect(b).not.toBeUndefined();
    expect(c).toBeUndefined();
  });
});

toBeLessThan et toBeGreaterThan

toBeGreaterThan et toBeLessThan permettent de vérifier si un élément est plus grand, ou s’il est plus petit, qu’un autre.

describe("The 'toBeLessThan' and 'toBeGreaterThan' matchers", function() {
  var a = 1,
      b = 2,
      c = 3;

  it("is for mathematical comparisons", function() {
    expect(a).toBeLessThan(b);
    expect(b).not.toBeGreaterThan(c);
    expect(c).not.toBeLessThan(a);
  });
});

toBeCloseTo

toBeCloseTo permet de vérifier si un nombre est proche d’un nombre, selon un certain nombre de décimales, donné en deuxième argument du matcher.

describe("The 'toBeCloseTo' matcher", function() {
  var a = 1.2,
      b = 1.25;

  it("is for precision math comparison", function() {
    expect(b).toBeCloseTo(a, 1);
    expect(b).not.toBeCloseTo(a, 2);
  });
});

En utilisant deux décimales dans l’exemple ci-dessous, toBeCloseTo considère que le deuxième chiffre décimal diffère pour les deux nombres choisis. Mettre le deuxième argument à 0 arrondit les nombres aux entiers.

toBeCloseTo est assez difficile à prendre en main. Je vous recommande de bien tester son comportement avant de le mettre en œuvre dans plusieurs de vos tests.

toThrow et toThrowError

toThrow permet de tester les erreurs. En utilisant ce matcher, Jasmine s’attend à recevoir une erreur, et c’est donc seulement en présence de celle-ci que la spec passera.

toThrowError permet de tester spécifiquement des erreurs. Ce matcher autorise en argument une expression régulière, une chaîne de caractères ou un type d’erreurs.

describe("The 'toThrow' matcher", function() {
  var f = function(){ throw new Error(); },
      g = function(){ throw new TypeError("I failed!"); };

  it("tests if a function throws an exception", function() {
    expect(f).toThrow();
  });

  it("tests a specific thrown exception", function() {
    expect(g).toThrowError(/fail/);
    expect(g).toThrowError("I");
    expect(g).toThrowError(TypeError);
  });
});

Des matchers personnalisés

Il est également possible de créer ses propres matchers. Il faut ajouter son matcher au sein du fichier contenant les specs qui doivent l’utiliser. Pour cela, il est possible d’utiliser beforeEach ou beforeAll.

Dans les versions de Jasmine supérieures à la 2.0, la fonction compare reçoit la valeur passée à la fonction expect comme étant son premier argument, la valeur réelle, et la valeur (si celle-ci existe) donnée au matcher comme étant son deuxième argument, la valeur attendue. Les matchers personnalisés prennent en argument deux paramètres : util, qui est un set de fonctions utiles pour les matchers, voir matchersUtil.js pour une liste détaillée ; et customEqualityTesters, qui a besoin d’être appelé si util.equals est utilisé.

Dans le cas présent ci-dessous, je crée un matcher ne prenant en considérant que la valeur réelle, actual, et je vérifie si celle-ci est paire grâce à util.equals. Cette fonction prend en paramètre la valeur réelle, la valeur attendue, et l’objet customEqualityTesters. La valeur réelle est ici, une opération avec modulo 2 qui consiste à vérifier si mon nombre est pair, et la valeur attendue est true. Si jamais cette opération donne un résultat égal à false, le matcher toBeEven me renvoie le message « Expected <number> to be even » et la spec échoue.

describe("The 'toBeEven' matcher", function() {
  beforeAll(function() {
    jasmine.addMatchers({
      toBeEven: function(util, customEqualityTesters) {
        return {
          compare: function(actual){
            return { pass: util.equals(actual%2==0, true, customEqualityTesters) }
          }
        }
        this.message = function() {
          return "Expected " + actual + " to be even";
        };
      }
    });
  });

  if('expects numbers to be even or not', function(){
    expect(2).toBeEven();
    expect(6857).not.toBeEven();
  });
});

Un peu de pratique est nécessaire pour bien comprendre comment mettre en place ses propres matchers. Mais vous verrez que les possibilités sont énormes, et que cela peut vous permettre d’avoir un code plus lisible si vos suites possèdent beaucoup de specs.

Écrire un premier test Jasmine

Ainsi, il est, par exemple, très simple de vérifier à l’aide de Jasmine, le bon comportement de la fonction du crible d’Eratosthenes présente ci-dessous. Cette fonction est censée retourner un tableau de tous les nombres premiers inférieurs à n.

function eratosthenes(n) {
  var detectprimes = new Array(n),
      primes = new Array();

  detectprimes[0] = false;
  detectprimes[1] = false;

  for(var i=2; i < detectprimes.length; i++)
    detectprimes[i] = true;

  for(var p=2; p < Math.sqrt(n); p++) {
    if(detectprimes[p]) {
      for(var j = p*p; j < n; j+= p)
        detectprimes[j] = false;
    }
  }

  for (var i = 0; i < n; i++)
    if(detectprimes[i]) primes.push(i);

  return primes;
}

Dans la suite créée, on souhaite obtenir un tableau de tous les nombres premiers en-dessous de 100. Pour cela, on utilise la fonction eratosthenes avec en paramètre le nombre 100.

Le test doit effectuer les vérifications suivantes. Ce tableau doit contenir 25 éléments. Parmi eux doivent figurer les nombres 5, 11, 43 et 97, choisis de façon totalement arbitraire. Mais les nombres 28, 60 et 99 ne doivent pas appartenir à ce tableau, car ils ne sont pas premiers.

describe('Prime numbers under 100 array', function(){
  var primes = eratosthenes(100);

  it('is truthy', function(){
    expect(primes).toBeTruthy();
  });

  it('is really an array', function(){
    expect(Array.isArray(primes)).toBe(true);
  });

  it('has 25 primes under 100', function(){
    expect(primes.length).toEqual(25);
  });

  it('contains 5, 11, 43, 97 as primes', function(){
    expect(primes).toContain(5);
    expect(primes).toContain(11);
    expect(primes).toContain(43);
    expect(primes).toContain(97);
  });

  it('does not contain 28, 60, 99', function(){
    expect(primes).not.toContain(28);
    expect(primes).not.toContain(60);
    expect(primes).not.toContain(99);
  });
});

WordPress 4.3, Billie Holiday

Copyright : William P. Gottlieb

Comme chaque version de WordPress depuis la 1.0, prénommée Miles Davis, la version 4.3 de WordPress porte le nom d’une légende de la musique jazz, Billie Holiday.

WordPress core developers share a love of jazz music, and all our major releases are named in honor of jazz musicians we personally admire.

Cette originalité est dûe au développeur fondateur de ce CMS open source, Matt Mullenweg. Ce passionné de l’écriture aime aussi la musique, avec un amour tout particulier pour les sonorités du saxophone. C’est d’ailleurs son affection pour cet instrument qui l’a conduit dans le monde du web et l’univers des blogs.

Cette nouvelle version de WordPress est sortie le 18 août 2015. Elle améliore, entre autres, le confort de l’utilisateur grâce à de nouvelles fonctionnalités.

 

Un formatage simplifié

L’un des sujets les plus excitants concernant cette nouvelle version de WordPress est la possibilité d’utiliser des raccourcis clavier pour mettre instantanément en forme du texte.

Il est en effet désormais possible, depuis la console visuelle d’un article, de pouvoir créer des titres, des citations, des listes ordonnées ou numérotées, dans le corps de texte, sans avoir à cliquer sur des boutons et sans jamais s’interrompre d’écrire. Cette fonctionnalité met en avant l’appartenance sémantique des éléments d’un site, tout en garantissant une optimisation du temps passé à les structurer.

Les quelques raccourcis désormais disponibles dans l’interface visuelle de WordPress sont décrits dans le paragraphe présent ci-dessous. Par ailleurs, si vous tapez une de ces combinaisons, mais ne souhaitez pas que le formatage automatique se mette en place, il suffit d’appuyer sur la touche Backspace de votre clavier.

        - space → liste <ul>
        * space → liste <ul>
      1. space → liste <ol>
      1) space → liste <ol>
          > text → citation <blockquote>
        ## text → titre de niveau 2 <h2>
      ### text → titre de niveau 3 <h3>
    #### text → titre de niveau 4 <h4>
  ##### text → titre de niveau 5 <h5>
###### text → titre de niveau 6 <h6>

Des mots de passe sécurisés

Une autre des grandes fonctionnalités proposées par la version 4.3 de WordPress est le nouveau système de gestion des mots de passe.

Tout d’abord, l’interface de la création d’un nouvel utilisateur du blog a été modifiée. Dans les versions antérieures à la version 4.3, il était possible, au moment de l’ajout d’un administrateur du blog, d’initialiser le mot de passe de ce nouvel utilisateur en le tapant deux fois. Un indicateur de sûreté était proposé à cet instant à l’utilisateur, lui recommandant d’utiliser au moins sept caractères, des lettres en minuscules et en majuscules, ainsi que des symboles.

Aujourd’hui, par défaut, le nouvel utilisateur reçoit un mot de passe automatiquement généré de manière aléatoire avec un indicateur de sécurité fort.

WordPress new password system

Bien évidemment, il est possible de réduire ce mot de passe, ou de complètement le modifier. WordPress vous signalera alors si celui-ci lui semble sûr, ou si au contraire celui-ci peut facilement être retrouvé. Si le mot de passe que vous choisissez est considéré comme étant faible, un nouveau champ Confirmation du mot de passe se présente dans l’interface.

WordPRess new password system with weak password

Un menu revisité

Grâce à la version 4.3 de WordPress, il est désormais possible de concevoir de nouveaux menus pour son blog depuis l’interface de personnalisation du thème. Il est donc possible de créer en temps réel un menu, de prévisualiser ce composant dans son environnement graphique et de sauvegarder l’évolution de celui-ci pour le mettre à disposition de tous.

L’interface de personnalisation de menu a originellement été proposée à l’aide du plugin Menu Customizer. Cette fonctionnalité existe désormais côté core de l’applicatif. Le principal objectif de cette fonctionnalité est de moderniser la gestion de menu tout en garantissant une expérience utilisateur optimale.

Ainsi, les lecteurs d’un blog n’ont plus à être impactés par des changements de menus intempestifs, car l’administrateur du blog peut mieux tester son environnement graphique avant toute nouvelle publication.

Des bugs corrigés

Une multitude de bugs provenant des versions précédentes de WordPress a été corrigée lors de l’élaboration de la version 4.3 de WordPress. Il est possible d’appréhender chacun des fixs apportés grâce à la liste des tâches corrigées que nous propose l’espace Make WordPress Core de WordPress.

Un hommage à Lady Day

Billie Holiday, aussi surnommée Lady Day, est considérée comme une des plus grandes légendes de jazz de l’histoire afro-américaine. Elle a révolutionné le monde de la musique avec ses vocalises improvisées et sa voix reconnaissable d’entre milles.

Billie Holiday tire son inspiration des classiques de Louis Armstrong et de Bessie Smith. Encore jeune adolescente, elle trouvait réconfort auprès de leurs chansons pendant les moments difficiles. À l’âge de 18 ans, elle est découverte par John Hammond dans un club de jazz de Harlem. Dès lors, son timbre métallique et acide, son phrasé nonchalant et sa souplesse rythmique marquent ses interprétations.

No two people on earth are alike, and it’s got to be that way in music or it isn’t music. – Billie Holiday

Cette année marque le centenaire de la naissance de Billie Holiday, née en avril 1915.

La diversité dans les équipes techniques

Copyright : O'Reilly Conferences

Laine Campbell est une architecte de base de données Oracle, MySQL et Cassandra. C’est une fervente entrepreneuse à l’origine de Blackbird.io notamment, travaillant aujourd’hui pour Pythian. Elle était invitée à la conférence Velocity qui se tenait à Barcelone en novembre dernier.

Laine Campbell nous y propose un sujet hors du commun pour cette conférence orientée sur la performance, avec une keynote intitulée Recruiting for diversity in tech. Elle nous y dresse un portrait des lieux de la diversité culturelle dans le monde technique actuel et souhaite faire prendre conscience aux organisations qu’elles y gagneront à être plus diversifiées.

La diversité, un challenge

Selon Laine Campbell, la diversité est un enjeu. Et la diversité des équipes est un atout pour une entreprise et pour ses employés. Mais c’est surtout quelque chose de bénéfique à toute personne dans le monde entier.

Partant de ce principe, il faut supposer que chacun est de bonne volonté, que chacun peut être ignorant vis-à-vis d’une facette culturelle d’autrui ; mais que cela ne doit pas empêcher la bonne communication dans une équipe. Il faut présumer des bonnes intentions de chacun.

Il faut encourager la culture du pardon, afin de permettre à tout le monde de s’exprimer sur un même pied d’égalité. Cela donne à chacun une chance de parler, d’apprendre et de se sentir suffisamment libre pour donner ses suggestions. Les points de vue de chacun sont intéressants, et ceux-ci dépendent forcément de son éducation, de son appartenance culturelle et de son parcours.

Enfin, il faut se rendre compte des privilèges que reçoivent certains et des préjudices que subissent les autres, dans le but de les éviter, de les éradiquer complètement.

La puissance de la diversité

Laine Campbell identifie deux types de diversité au cours de sa présentation : la diversité dite inhérente et la diversité dite acquise.

La diversité inhérente représente la forme de diversité qui reste inchangée la plupart du temps, la diversité avec laquelle naît chacun d’entre nous. Il s’agit par exemple du genre, de la classe sociale, de la race, de la nationalité, de l’origine ethnique, etc..

La diversité acquise représente la forme de diversité que l’on gagne alors que nous évoluons en tant que personne. Il s’agit de la facilité avec laquelle on s’exprime, de la perception différente des cultures grâce aux voyages, du parcours militaire, de la culture générale, de la perspicacité liée à des connaissances pratiques, etc..

D’après Laine Campbell, si une personne est salariée d’une entreprise possédant ces deux degrés de diversité, cette personne a 75% de chance de plus de faire entendre ses idées par le marketing. Et pour une entreprise, si ses employés sont capables de faire ceci, cela lui donne 70% de chance de plus de prendre le large sur de nouveaux marchés et 45% de plus d’améliorer ses parts de marché.

Apple, Microsoft et Google, sont dans cet ordre, les trois marques les plus estimées dans le monde technique. Elles sont aussi parmi les trois marques les plus diversifiées humainement, et leurs plafonds de marché coïncident avec cette métrique.

Ethnic diversity in tech

Un autre constat est fait par Laine Campbell : le nombre de techniciens est finalement assez faible vis-à-vis des besoins qu’ont les entreprises aujourd’hui. Leur salaire est donc en hausse significative.

Selon indeed.com, la moyenne des salaires des ingénieurs est 77% plus haute que la moyenne des autres salaires aux États-Unis. Mais cela coûte énormément aux entreprises qui doivent continuellement se battre contre la concurrence et qui sont continuellement en train de perdre des employés.

Les entreprises dans le monde technique dépensent finalement plus d’argent pour une population moins grande ; ce qui implique moins d’esprit compétitif dans leurs équipes, moins de code qualitatif et moins de partage d’idées. Selon Laine Campbell, en créant des sociétés plus diversifiées, une entreprise sera en mesure de créer de meilleurs produits et d’améliorer ses parts de marché.

Trends software engineer

La recherche de talents

Les dirigeants d’une entreprise comme les personnes responsables d’un applicatif open source sont chargés de construire les équipes contributrices au développpement de ce projet, de déterminer quelles personnes sont susceptibles de leur convenir parfaitement, de donner à ces personnes l’envie de participer activement.

Dans les schémas actuels, ce groupe de personnes arrive à ses fins en contactant des personnes déjà présentes sur leurs réseaux, des personnes qui faisaient partie de leurs promotions, des personnes avec lesquelles ils ont déjà travaillé ou encore des personnes rencontrées dans des meetups.

D’après Laine Campbell, cette méthode de recrutement est le meilleur moyen de tourner en rond, d’enclencher une boucle infinie. Cette technique de recherche de candidats favorise à ce que les personnes qui intègrent le projet ou l’entreprise soient des personnes possédant la même culture, la même diversité que les personnes déjà présentes.

Et si des personnes différentes, des femmes, des personnes de couleur, viennent malgré à tout à intégrer l’organisation, elles deviennent sujettes aux day to day beatdowns pour reprendre l’expression de notre interlocutrice, aux difficultés quotidiennes qui les empêchent de se sentir bien insérées professionnellement.

Pour une femme, il peut s’agir de se voir retirer un projet parce qu’elle refuse de sortir avec quelqu’un ou parce qu’elle est considérée comme étant moins compétente à cause de son genre. Cela peut avoir la forme de propos racistes, sexistes et/ou homophobes. C’est aussi voir ses idées se faire voler par un autre après la lui avoir soumis et s’être fait rire au nez. D’après Laine Campbell, le manque de diversité provoque ce genre d’incommodités dans le monde professionnel.

La méritocratie en place dans le monde technique met essentiellement l’accent sur une recherche de candidats dédiés complètement à leur vie professionnelle, prêts à faire 16 heures de travail par jour ; ce qui, comme le souligne Laine Campbell, est loin d’être le cas pour tout le monde. Le recrutement est fait pour trouver des personnes dont la personnalité colle à celle des personnes déjà présentes, pour garantir une homogénéité des comportements humains. Et les candidats doivent fonctionner de la même façon en cas de désaccord, doivent finalement penser pareil. Tout est fait pour conditioner au mieux la culture du confort. Mais rien ne mentionne plus les compétences ni les capacités…

Le recrutement revisité

Comment faire entrer tout le monde dans la danse ? Il faut revoir le dynamisme autour du recrutement. Le recrutement doit être la tâche de tout le monde. Chacun peut faire en sorte que la structure de sa compagnie évolue.

L’approche assez drastique pourrait être la suivante : faire en sorte que pour un pôle technique, 50% des candidats soient des femmes et 25% des candidats soient des personnes de couleur. L’intervention de nouveaux cabinets de recrutement et la participation de l’entreprise à des meetups originaux lui permettra d’être mieux perçue, et d’être plus visible pour la communauté technique.

En guise d’illustrations, Laine Campbell nous présente le cas d’Etsy, un site de vente en ligne spécialisé dans les créations faites à la main. Etsy s’est donné les moyens de diversifier sa population en passant des partenariats avec des écoles, notamment avec Hacker School. Le but de l’expérience était de recruter des personnes encore débutantes professionnellement, pour leur apprendre le métier et faire en sorte qu’elles évoluent au sein de la société. Pour Etsy, c’était une réelle opportunité de trouver des personnes capables, énergétiques, désireuses d’apprendre, pleines de bonnes intentions.

Une autre manière de recruter différemment serait d’avoir des CVs et des lettres de motivation dépourvues de photos, et même dépourvues de noms (si possible) au moment de l’examen d’un dossier. Toute l’attention du recruteur serait sur les résultats de tests, la qualité du code et les expériences professionnelles précédentes du candidat. Ce serait un moyen de garantir au recruteur d’être focalisé sur l’important, et non pas sur des considérations humaines.

Une culture en marche

Une fois que cette diversité est en marche, il faut parvenir à bien intégrer ces personnes. Il faut faire en sorte qu’elles se sentent bien accueillies dans l’entreprise. Pour garantir un certain niveau d’ordre, un règlement d’intérieur peut être rédigé.

Cela peut paraître simpliste, mais les quelques règles énoncées encourageront la bonne conduite de chacun, permettront à tous de savoir quels agissements sont tolérés et surtout quels comportements sont à exclure au quotidien. L’éducation est le meilleur moyen de parvenir à une bonne cohésion dans les équipes.

Il faut éliminer tout préjudice possible. Il faut respecter les compétences techniques de chacun et faire en sorte que les méritocraties mises en place fonctionnent avec moins de focalisation sur la diversité.

And with that, you can actually build some amazing diversity teams, which will encourage your company to do better, you to do better, you to get more opportunity and growth in the organization, and probably bigger bonuses and that’s a good part of the opportunity as well.

Problème #3 du project Euler

Copyright : geir tønnessen

« The prime factors of 13195 are 5, 7, 13 and 29.
What is the largest prime factor of the number 600851475143 ? »

Le troisième problème du projet Euler reprend les notions mathématiques de nombres premiers et de facteurs premiers. Un nombre premier est un nombre entier supérieur à 1 qui n’a pour diviseurs que 1 et lui-même.

Les facteurs premiers d’un nombre entier, quant à eux, sont l’ensemble des nombres premiers qui divisent entièrement cet entier. Par exemple, les facteurs premiers du nombre 70 sont 2, 5 et 7. Comme le décrit l’énoncé de ce problème, les facteurs premiers de 13 195 sont 5, 7, 13 et 29.

La factorisation en nombres premiers d’un entier peut également être exprimée à l’aide de puissances. En guise d’illustration, le nombre 300 peut se décomposer de la manière suivante : 2 x 2 x 3 x 5 x 5. Pour simplifier cette écriture, le carré est souvent utilisé : 2² x 3 x 5².

Algorithme de la solution

Pour trouver le plus grand des facteurs premiers d’un nombre entier x, on considère comme probable diviseur de ce nombre tous les entiers supérieurs à 1, 2 étant le premier des nombres premiers.

Si l’entier considéré divise entièrement x, on divise successivement x par ce nombre, jusqu’à que ce nombre ne soit plus un facteur de x. Cette opération garantit la primalité du nombre considéré car tous les plus petits facteurs de x auront d’ores-et-déjà été traités.

Une première écriture de cet algorithme donnerait le résultat suivant. La fonction obtenue s’exécute en 12.57 millisecondes sur mon ordinateur.

function problem3(){
  var x = 600851475143,
      largest = 1,
      k = 2;
  while(x > 1){
    // If k is a factor of x
    if(x % k == 0){
      largest = k;
      x = x / k;
      while(x % k == 0) x = x / k;
    }
    k++;
  }
  // Give the largest prime factor of x
  return largest;
}

Une première évolution de ce code serait de traiter le nombre 2 à part, car 2 est le seul nombre premier de valeur paire. Cela nous permet par la suite d’utiliser la même boucle, en incrémentant de 2 chaque potentiel candidat à être facteur. On testera donc de manière successive les nombres 3, 5, 7, etc..

Ce nouvel algorithme s’exécute en 3.22 millisecondes sur mon ordinateur.

function problem3(){
  var x = 600851475143,
      largest = 1,
      k = 3;
  // If 2 is a factor of x, we treat it separately...
  if(x % 2 == 0){
    x = x / 2;
    largest = 2;
    while(x % 2 == 0) x = x / 2;
  }
  // ... so we can increase factor with 2 every iteration
  while(x > 1){
    if(x % k == 0){
      largest = k;
      x = x / k;
      while(x % k == 0) x = x / k;
    }
    k += 2;
  }
  // Give the largest prime factor of x
  return largest;
}

Il est encore possible d’améliorer l’efficacité de cette fonction en considérant que chaque entier x ne peut avoir au maximum qu’un seul nombre premier supérieur à sa racine carrée.

Après avoir divisé de manière successive un des nombres premiers trouvés, on calcule la racine carré de la valeur restante de x. Si le facteur considéré est supérieur à la racine carrée de x, alors la valeur restante de x est le plus des grands des nombres premiers de x.

Cette nouvelle version s’exécute cette fois en 1.84 milliseconde chez moi !

function problem3(){
  var x = 600851475143,
      largest = 1,
      k = 3;
  // If 2 is a factor of x, we treat it separately...
  if(x % 2 == 0){
    x = x / 2;
    largest = 2;
    while(x % 2 == 0) x = x / 2;
  }
  // ... so we can increase factor with 2 every iteration
  // This loop runs only if k is not bigger than the square
  // root of the remaining x
  while(x > 1 && k<= Math.sqrt(x)){
    if(x % k == 0){
      largest = k;
      x = x / k;
      while(x % k == 0) x = x / k;
    }
    k += 2;
  }
  // Give the largest prime factor of x
  if(x == 1) return largest;
  else return x;
}

L’algorithme du sieve of Eratosthenes

Copyright : Fraser Mummery

Eratosthenes of Cyrene est un mathématicien, géographe, poète, astronome et théoricien de la musique né en Grèce antique. Il a été un grand penseur, à l’origine notamment des premières cartes représentatives du monde, tel que celui-ci était connu à l’époque. C’est à lui que l’on doit entre autres, le jour bissextile (le 29 février), de nombreuses découvertes en matière de géographie dont une approximation raisonnable du diamètre de la Terre, et le fameux crible d’Ératosthène.

Cet algorithme est une manière efficace de retrouver tous les nombres premiers. Celui-ci consiste à tester la primalité des nombres de 2 à n selon la méthode décrite ci-après.

L’algorithme du crible d’Ératosthène décrypté

Considérons une liste de nombres entiers de 2 à n, 2 étant le premier des nombres premiers. On récupère tous les multiples de 2 appartenant à cette liste, et on les marque comme étant non premiers : par définition, tout multiple de 2 est divisible par 2. Le multiple d’un nombre ne peut donc pas être premier.

On cherche ensuite le premier des nombres supérieurs à 2 n’étant pas marqué dans la liste, et on répète la précédente instruction, à savoir marquer comme étant non premiers tous les multiples de ce nombre. On récupère ainsi le nombre 3 et on parcourt ses multiples afin de les marquer comme nombre non premier.

Chacune de ces opérations est répétée jusqu’à ce que l’on arrive à la limite de cette liste, le nombre n. Quand l’algorithme se termine, tous les nombres qui n’auront pas été marqués dans la liste constituent la séquence de nombres premiers inférieurs à n.

Animation of the Sieve of Eratosthenes

Chacun des nombres restants une fois l’algorithme terminé est nécessairement nombre premier, car tous les multiples des nombres inférieurs auront déjà été marqués. Il se peut, par ailleurs, qu’un multiple ait déjà été marqué : c’est le cas du nombre 6 par exemple. Ce nombre est marqué originellement comme étant non premier car il est multiple de 2. 6 étant également multiple de 3, il pourrait éventuellement être marqué une deuxième fois.

Une évolution de l’algorithme énoncé ci-dessus serait de commencer à marquer tous les multiples d’un nombre premier à partir du carré de celui-ci, car tous les plus petits multiples de celui-ci auront d’ores-et-déjà été marqués. Cela signifie aussi que l’algorithme peut se terminer lorsque le carré d’un des nombres premiers trouvés est supérieurs à n.

…en JavaScript

Ci-dessous, une des écritures possibles de cet algorithme en JavaScript, permettant d’obtenir tous les nombres premiers inférieurs à n. detectprimes est un tableau de n booléens. On attribue la valeur true à l’ensemble des nombres de 2 à n, 0 et 1 ne faisant pas partie de cet ensemble sont initialisés avec la valeur false.

Une boucle for est mise en place, avec une limite de √n. À chaque nouvelle itération sur le tableau de n nombres, on vérifie si p est premier – si p est égal à true – et seulement à cette condition, on évalue tous les multiples de p supérieurs au carré de p, afin de les marquer à false, comme étant non premiers donc.

Il ne reste ensuite qu’à parcourir les éléments du tableau detectprimes, afin de récupérer tous les nombres premiers inférieurs à n.

function eratosthenes(n) {
  var detectprimes = new Array(n),
      primes = new Array();

  // Set detectprimes with boolean values
  detectprimes[0] = false;
  detectprimes[1] = false;
  for(var i = 2; i < detectprimes.length; i++)
    detectprimes[i] = true;

  // Mark all multiples as false
  for(var p = 2; p < Math.sqrt(n); p++) {
    if(detectprimes[p]) {
      for(var j = p*p; j < n; j += p)
        detectprimes[j] = false;
    }
  }

  // Get all the prime numbers
  for (var i = 0; i < n; i++)
    if(detectprimes[i]) primes.push(i);
  return primes;
}

Pour vérifier le bon comportement de la fonction que je vous propose, voici une représentation textuelle de l'image qui schématise l'algorithme proposé par Ératosthène.

En exécutant le code présent ci-après, vous pourrez mieux appréhender le déroulement du crible d'Ératosthène. Cette nouvelle version, proposant des commentaires, à l'aide de console.log est bien évidemment moins efficace en terme de performance, mais vous permettra de suivre chacun des tests effectués à chacune des itérations de la boucle.

function eratosthenes(n) {
  var detectprimes = new Array(n),
      primes = new Array();
  console.log('I want to know which numbers below ' + n + ' are primes.');

  // Set detectprimes with boolean values
  detectprimes[0] = false;
  detectprimes[1] = false;
  for(var i = 2; i < detectprimes.length; i++)
    detectprimes[i] = true;

  // Mark all multiples as false
  for(var p = 2; p < Math.sqrt(n); p++) {
    if(detectprimes[p]) {
      console.log(p + ' is a prime, let\'s mark all its multiples below ' + n + '.');
      for(var j = p*p; j < n; j += p){
        console.log(j + ' is a multiple of '+p+', so ' + j + ' is not a prime.');
        detectprimes[j] = false;
      }
    }else{
      console.log(p + ' is not a prime, so the loop continues.');     
    }
  }
  console.log(p + ' is not smaller than ' + Math.sqrt(n) + ': end of the loop.');

  // Get all the prime numbers
  var _text = 'The primes below ' + n + ' are: ';
  for (var k = 0; k < n; k++) {
    if (detectprimes[k]) {
      primes.push(k);
      if (primes.length == 1) _text += k;
      else _text += ', ' + k;
    }
  }
  console.info(_text + '.');
  return primes;
}
eratosthenes(121);

Vous aurez dans votre console la sortie suivante :

I want to know which numbers below 121 are primes.

2 is a prime, let’s mark all its multiples below 121.
4 is a multiple of 2, so 4 is not a prime.
6 is a multiple of 2, so 6 is not a prime.
8 is a multiple of 2, so 8 is not a prime.
10 is a multiple of 2, so 10 is not a prime.
12 is a multiple of 2, so 12 is not a prime.
14 is a multiple of 2, so 14 is not a prime.
16 is a multiple of 2, so 16 is not a prime.
18 is a multiple of 2, so 18 is not a prime.
20 is a multiple of 2, so 20 is not a prime.
22 is a multiple of 2, so 22 is not a prime.
24 is a multiple of 2, so 24 is not a prime.
26 is a multiple of 2, so 26 is not a prime.
28 is a multiple of 2, so 28 is not a prime.
30 is a multiple of 2, so 30 is not a prime.
32 is a multiple of 2, so 32 is not a prime.
34 is a multiple of 2, so 34 is not a prime.
36 is a multiple of 2, so 36 is not a prime.
38 is a multiple of 2, so 38 is not a prime.
40 is a multiple of 2, so 40 is not a prime.
42 is a multiple of 2, so 42 is not a prime.
44 is a multiple of 2, so 44 is not a prime.
46 is a multiple of 2, so 46 is not a prime.
48 is a multiple of 2, so 48 is not a prime.
50 is a multiple of 2, so 50 is not a prime.
52 is a multiple of 2, so 52 is not a prime.
54 is a multiple of 2, so 54 is not a prime.
56 is a multiple of 2, so 56 is not a prime.
58 is a multiple of 2, so 58 is not a prime.
60 is a multiple of 2, so 60 is not a prime.
62 is a multiple of 2, so 62 is not a prime.
64 is a multiple of 2, so 64 is not a prime.
66 is a multiple of 2, so 66 is not a prime.
68 is a multiple of 2, so 68 is not a prime.
70 is a multiple of 2, so 70 is not a prime.
72 is a multiple of 2, so 72 is not a prime.
74 is a multiple of 2, so 74 is not a prime.
76 is a multiple of 2, so 76 is not a prime.
78 is a multiple of 2, so 78 is not a prime.
80 is a multiple of 2, so 80 is not a prime.
82 is a multiple of 2, so 82 is not a prime.
84 is a multiple of 2, so 84 is not a prime.
86 is a multiple of 2, so 86 is not a prime.
88 is a multiple of 2, so 88 is not a prime.
90 is a multiple of 2, so 90 is not a prime.
92 is a multiple of 2, so 92 is not a prime.
94 is a multiple of 2, so 94 is not a prime.
96 is a multiple of 2, so 96 is not a prime.
98 is a multiple of 2, so 98 is not a prime.
100 is a multiple of 2, so 100 is not a prime.
102 is a multiple of 2, so 102 is not a prime.
104 is a multiple of 2, so 104 is not a prime.
106 is a multiple of 2, so 106 is not a prime.
108 is a multiple of 2, so 108 is not a prime.
110 is a multiple of 2, so 110 is not a prime.
112 is a multiple of 2, so 112 is not a prime.
114 is a multiple of 2, so 114 is not a prime.
116 is a multiple of 2, so 116 is not a prime.
118 is a multiple of 2, so 118 is not a prime.
120 is a multiple of 2, so 120 is not a prime.

3 is a prime, let’s mark all its multiples below 121.
9 is a multiple of 3, so 9 is not a prime.
12 is a multiple of 3, so 12 is not a prime.
15 is a multiple of 3, so 15 is not a prime.
18 is a multiple of 3, so 18 is not a prime.
21 is a multiple of 3, so 21 is not a prime.
24 is a multiple of 3, so 24 is not a prime.
27 is a multiple of 3, so 27 is not a prime.
30 is a multiple of 3, so 30 is not a prime.
33 is a multiple of 3, so 33 is not a prime.
36 is a multiple of 3, so 36 is not a prime.
39 is a multiple of 3, so 39 is not a prime.
42 is a multiple of 3, so 42 is not a prime.
45 is a multiple of 3, so 45 is not a prime.
48 is a multiple of 3, so 48 is not a prime.
51 is a multiple of 3, so 51 is not a prime.
54 is a multiple of 3, so 54 is not a prime.
57 is a multiple of 3, so 57 is not a prime.
60 is a multiple of 3, so 60 is not a prime.
63 is a multiple of 3, so 63 is not a prime.
66 is a multiple of 3, so 66 is not a prime.
69 is a multiple of 3, so 69 is not a prime.
72 is a multiple of 3, so 72 is not a prime.
75 is a multiple of 3, so 75 is not a prime.
78 is a multiple of 3, so 78 is not a prime.
81 is a multiple of 3, so 81 is not a prime.
84 is a multiple of 3, so 84 is not a prime.
87 is a multiple of 3, so 87 is not a prime.
90 is a multiple of 3, so 90 is not a prime.
93 is a multiple of 3, so 93 is not a prime.
96 is a multiple of 3, so 96 is not a prime.
99 is a multiple of 3, so 99 is not a prime.
102 is a multiple of 3, so 102 is not a prime.
105 is a multiple of 3, so 105 is not a prime.
108 is a multiple of 3, so 108 is not a prime.
111 is a multiple of 3, so 111 is not a prime.
114 is a multiple of 3, so 114 is not a prime.
117 is a multiple of 3, so 117 is not a prime.
120 is a multiple of 3, so 120 is not a prime.

4 is not a prime, so the loop continues.

5 is a prime, let’s mark all its multiples below 121
25 is a multiple of 5, so 25 is not a prime.
30 is a multiple of 5, so 30 is not a prime.
35 is a multiple of 5, so 35 is not a prime.
40 is a multiple of 5, so 40 is not a prime.
45 is a multiple of 5, so 45 is not a prime.
50 is a multiple of 5, so 50 is not a prime.
55 is a multiple of 5, so 55 is not a prime.
60 is a multiple of 5, so 60 is not a prime.
65 is a multiple of 5, so 65 is not a prime.
70 is a multiple of 5, so 70 is not a prime.
75 is a multiple of 5, so 75 is not a prime.
80 is a multiple of 5, so 80 is not a prime.
85 is a multiple of 5, so 85 is not a prime.

90 is a multiple of 5, so 90 is not a prime.
95 is a multiple of 5, so 95 is not a prime.
100 is a multiple of 5, so 100 is not a prime.
105 is a multiple of 5, so 105 is not a prime.
110 is a multiple of 5, so 110 is not a prime.
115 is a multiple of 5, so 115 is not a prime.
120 is a multiple of 5, so 120 is not a prime.

6 is not a prime, so the loop continues.

7 is a prime, let’s mark all its multiples below 121.
49 is a multiple of 7, so 49 is not a prime.
56 is a multiple of 7, so 56 is not a prime.
63 is a multiple of 7, so 63 is not a prime.
70 is a multiple of 7, so 70 is not a prime.
77 is a multiple of 7, so 77 is not a prime.
84 is a multiple of 7, so 84 is not a prime.
91 is a multiple of 7, so 91 is not a prime.
98 is a multiple of 7, so 98 is not a prime.
105 is a multiple of 7, so 105 is not a prime.
112 is a multiple of 7, so 112 is not a prime.
119 is a multiple of 7, so 119 is not a prime.

8 is not a prime, so the loop continues.

9 is not a prime, so the loop continues.

10 is not a prime, so the loop continues.

11 is not smaller than 11, end of the loop.

The primes below 121 are: 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113.

Pour aller plus loin : bien d'autres algorithmes proposent de récupérer l'ensemble des nombres premiers, d'autres mêmes jugés encore plus rapides d'exécution que le crible d'Ératosthène comme le sieve of Atkins ou encore le sieve of Sundaram, pour ne citer qu'eux.

Mais le sieve of Eratosthenes que je vous propose aujourd'hui est l'un des plus simples à écrire, et il a la particularité de dater du IIIème siècle avant Jésus-Christ, une prouesse mathématique pour l'époque !

Problème #2 du project Euler

Copyright : Michæl Paukner

« Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be: 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, …
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms. »

Afin de résoudre ce problème du projet Euler, il est important, dans un premier temps, de se consacrer à l’appréhension de ce que ce sont les séquences Fibonacci. En mathématiques, la séquence Fibonacci se définit comme une séquence dans laquelle chaque nombre est obtenu en effectuant la somme des deux termes précédents.

La formule mathématique associée est donc la suivante : F(n) = F(n-1) + F(n-2) avec F(0) = 0 et F(1) = 1. On appelle F(0) et F(1) les termes initiaux de cette suite logique, ceux qui permettent d’en déduire les nombres suivants. Les nombres Fibonacci constituent la séquence A000045 sur The On-line Encyclopedia of Integer Sequences. Ci-dessous sont représentés les vingt premiers termes de la séquence Fibonacci.

F(0) F(1) F(2) F(3) F(4)
0 1 1 2 3
F(5) F(6) F(7) F(8) F(9)
5 8 13 21 34
F(10) F(11) F(12) F(13) F(14)
55 89 144 233 377
F(15) F(16) F(17) F(18) F(19)
610 987 1 597 2 584 4 181

L’énoncé du problème #2 du projet Euler nous propose de trouver la somme de toutes les valeurs paires n’excédant pas 4 000 000. Il s’agit donc de considérer la séquence Fibonacci, de telle sorte qu’à chaque nouveau terme étant pair, celui-ci est ajouté à une variable sum, dont la valeur ne cessera d’augmenter que lorsque l’on aura atteint la limite proposée, égale à 4 000 000.

Les deux termes initiaux de la séquence Fibonacci sont représentés ci-dessous par les variables x et y respectivement égales à 0 et à 1. Ces variables possèdent une valeur croissante dans le temps à la condition que la variable y, représentant systématiquement le deuxième terme à un instant t, ne dépasse jamais la limite imposée. Une variable intermédiaire temp calcule le troisième terme créé à partir de la somme de x et y. x, premier terme de la séquence à un instant t, devient alors égal à y, qui lui-même prend la valeur de temp. À chaque nouvelle itération, on ajoute à la variable sum la valeur de la variable y si celle-ci est paire.

function problem2(){
  var limit = 4000000,
      sum = 0,
      x = 0,
      y = 1;

  while(y < limit){
    if(y%2==0) sum += y;
    var temp = x + y;
    x = y;
    y = temp;
  }
  return sum;
}

problem2();

En clair, lors de la première itération de cette boucle, on a : x = F(0) et y = F(1). temp représente d'abord F(2) et est donc égal à F(0) + F(1), soit x +y. x prend ensuite la valeur de y donc x = F(1) = 1 ; y prend la valeur de temp donc y = F(2) = 1.

Lors de la deuxième itération de la boucle, on a donc : x = F(1) et y = F(2). temp va représenter F(3), et donc être égal à F(1) + F(2), soit x +y. x prend ensuite la valeur de y donc x = F(2) = 1 ; y prend la valeur de temp donc y = F(3) = 2.

À la troisième itération de cette boucle, y étant égal à 2, chiffre pair, sera ajouté à sum. Et ainsi de suite, jusqu'à ce que y dépasse 4 000 000.

La fonction présente ci-dessus s'exécute en 0.12 milliseconde.

Quand la performance crée de la valeur

Copyright : O'Reilly Conferences

Au cours de la première journée de keynotes de la conférence Velocity qui se tenait à Barcelone, j’ai assisté à la brillante prestation de Monica Pal, venue nous présenter The Impatience Economy, Where Velocity Creates Value. Monica Pal est une ingénieure hautement diplômée. Elle a commencé sa carrière dans le département de recherche et de développement d’Apple et travaille maintenant à la construction d’infrastructures commerciales chez Aerospike.

L’indice de l’impatience

Monica Pal décide très rapidement de mettre l’accent sur l’impatience. La notion d’impatience nous renvoie à l’incapacité de quelqu’un à pouvoir attendre quelque chose de manière calme et posée. Sur un ton enjoué, l’intervenante nous cite des cas d’impatience de la vie courante : celui d’un bébé qui n’obtient pas très rapidement ce qu’il souhaite ou celui d’une personne affamée qui n’arrive plus à garder les idées claires… Ces différentes analogies sont une parfaite introduction à The « Impatience Index », l’étude menée par Kana Software sortie au cours du mois de janvier 2014.

Kana Software est une entreprise proposant des services de monitoring et des solutions de cloud computing. On apprend, grâce à leur analyse, que la patience n’est plus une qualité très répandue de nos jours. En effet, il y a quelques années, les gens étaient capables d’attendre dix jours le facteur pour recevoir des informations de leurs proches. Aujourd’hui, la nouvelle génération considère que 10 minutes d’attente sont amplement suffisantes. Les 18-24 sont d’ailleurs les plus impatients : toutes les 9 minutes 50 secondes en moyenne, ils regardent leurs téléphones à l’affût de nouvelles notifications. Ils regardent leurs smartphones pour tuer le temps, quand ils sont dans une file d’attente, quand ils font du shopping, en regardant la télévision, quand ils étudient… Et, comme le dit si bien Monica Pal, même quand ils attendent, ils détestent attendre ! Cette idée avait d’ores-et-déjà été énoncée par Mike Krieger, le co-fondateur d’Instagram : « Mobile experiences fill gaps while we wait / No one wants to wait while they wait ».

Les attentes du client moyen

Monica Pal nous présente ensuite une vidéo YouTube de Luke Wroblewski, qui nous incite à trouver la meilleure navigation possible pour les utilisateurs d’un site mobile. Luke Wroblewski, auteur par exemple du fameux livre Mobile First pour A Book Apart, explique comment quelque chose de valorisant, quelque chose d’efficace, peut apporter en termes d’expérience utilisateur.

Decoding the new consumer mind : How and why we shop and buy est un livre, écrit par Kit Yarrow, plein de bon sens quant à l’évolution de la société de consommation. L’utilisateur moyen est plus facilement distrait que celui des années 90 et est moins tolérant pour quasi tout ce qui demande de la patience. Ce livre, que nous propose ainsi Monica Pal, est une nouvelle façon d’appréhender comment nos cerveaux, nos esprits et nos perceptions évoluent en parallèle des avancées technologiques. Ce monde de nouvelles plateformes qui émergent nous conditionne à vouloir de la rapidité dans tous nos échanges.

Le consommateur moyen de l’époque avait une approche intellectuelle et réfléchie vis-à-vis des interfaces. Aujourd’hui, les utilisateurs ont une approche bien plus instinctive, liée à l’émotionnel. Quotidiennement, l’utilisateur est dans un environnement digital de couleurs, d’images et de vidéos dans lesquelles il perçoit des gens faire quelque chose qu’il va « aimer », « suivre » et relayer. Il passe son temps à cliquer et à réagir instantanément plutôt qu’à taper sur son clavier. Et donc, selon Monica Pal, cette logique nous mènerait, nous développeurs, à toujours anticiper les comportements de nos utilisateurs. Nous devons sublimer nos interfaces et les rendre intelligibles pour un utilisateur moyen, qui lui, n’aura aucune envie de passer du temps à « comprendre » où se trouvent nos fonctionnalités. Nous devons personnaliser l’expérience utilisateur.

Une étude récente chez Radware démontre qu’une simple seconde de chargement de contenu plus rapide apporte de la valeur significative.

Les impacts d’une bonne structure

De nombreux sites et de nombreux acteurs dans le monde du media ont un système économique lié à la publicité digitale. Aujourd’hui, la publicité est ce qui crée de la valeur fondatrice de certaines expériences sociales, selon Monica Pal. Une des technologies les plus exploitées à l’heure actuelle consiste à allouer en temps réel une impression publicitaire à un annonceur et d’en déterminer le prix en fonction de son format et de son contexte. Cette nouvelle infrastructure, appelée le Real-Time Bidding (RTB), doit donc permettre aux annonceurs en seulement quelques millisecondes d’enchérir sur un emplacement publicitaire, selon les informations connues sur un utilisateur donné. En clair, en un court laps de temps, ils doivent pouvoir extraire des données précises sur cette personne afin de lui proposer un contenu personnalisé, qui va nécessairement modifier son expérience.

Aujourd’hui, quelque soit le site web que vous parcourez, quelle que soit l’application que vous utilisez, votre expérience utilisateur peut être à tout moment bouleversée par ces infrastructures. La rapidité d’exécution apparaît donc un facteur clé de réussite. Monica Pal nous prend l’exemple d’AppNexus, une société américaine spécialisée dans la publicité digitale en temps réel. AppNexus propose un nouveau degré de vitesse : leur base de données leur permet d’effectuer 3 millions de lectures et 1.5 million d’écritures par seconde.

AppLovin, une autre société proposant une technologie RTB orientée applications, traite plus de 20 milliards de requêtes par jour, représentant 100 millions de chiffre d’affaires. Ils utilisent une nouvelle technologie de stockage Flash, au lieu d’utiliser de la RAM, ce qui leur permet de bien répartir leur performance sans ajouter un nombre indécent de serveurs à leur infrastructure.

La mise en cache des données les plus utilisées (dites chaudes) dans une solution de stockage Flash permet de ne plus devoir lire les données à partir des disques durs, d’où une réduction des temps de latence et, de fait, une amélioration des performances des applications.

Christophe Menard, « Optez pour le stockage Flash »

Monica Pal tient donc à démontrer avec toute cette analyse, la nécessité de travailler la partie front-end d’un site web, mais surtout de ne pas négliger la vitesse d’infrastructure qui soutient cette plateforme, qui peut, elle aussi, être gage de performance. You, guys, are focused on the web front end, but there’s a new degree of velocity that is emerging, creating a new kind of value out there.

Les fonctions récursives en JavaScript

Copyright : Dennis JArvis

To iterate is human, to recurse divine. – L. Peter Deutsch

La récursivité est un grand concept de la programmation : il s’agit d’une méthode permettant d’obtenir une solution à un problème en utilisant des instances plus petites de ce même problème. En clair, une fonction est donc dite récursive si elle s’appelle elle-même.

La récursivité est une approche de la programmation un peu complexe au premier abord, puisqu’elle s’oppose à la programmation itérative. Mais elle propose des avantages indéniables : sa grande force est de pouvoir résoudre un problème en le divisant en une collection de sous-problèmes, chacun d’entre eux étant résolu par une solution évidente.

Pour bien appréhender ce concept, le sous chapitre suivant est proposé en guise de rappel. Il vous permettra de faire un parallèle avec l’écriture récursive, que je vous explique dans un second temps.

Une boucle, des itérations

Une boucle est une séquence d’instructions qui se répétera jusqu’à ce qu’une certaine condition soit remplie. Cette condition permettant de sortir de la boucle peut être définie à l’aide d’un compteur. On peut ainsi définir une boucle comme étant un bloc de code qui sera exécuté au moins une fois. Et chacune de ces exécutions est appelée une itération.

Les boucles sont plutôt simples à écrire, faciles à comprendre, et elles permettent de gagner un temps non négligeable, qui en plus évite la répétition de code pour chacune des itérations.

En guise d’illustration, je vous propose l’implémentation de la notion mathématique suivante : la factorielle. La factorielle d’un nombre est le produit de tous les entiers de 1 à ce nombre. Ainsi, la factorielle du nombre 5 est égale au produit de 1 x 2 x 3 x 4 x 5. Elle est donc égale à 120. Je crée donc ici une fonction factorial qui va, au moyen de la boucle for, proposer le résultat de factorielle x de manière itérative.

function factorial(x) {
  var result = 1;
  for (var i = 1; i <= x; i++)
    result = result * i;
  return result;
}

factorial(5); // output : 120

Comme vous pouvez le voir, on utilise ici un compteur qui va s'incrémenter en répétant l'action de produire la multiplication entre le résultat précédemment obtenu et ce même compteur. A chaque itération de la boucle, ce compteur change donc de valeur.

Cas de base, cas de propagation

Afin que la récursivité soit effective, deux fonctionnalités clés doivent nécessairement être implémentées. Il s'agit du cas de base et du cas de propagation, aussi parfois appelé simplement le cas récursif.

Le cas de base représente l'ensemble des lignes de code qui permet l'arrêt de la récursion. Habituellement, cet ensemble débute avec une clause conditionnelle comme if. Si cette notion n'est pas mise en place, la fonction sera répétée de manière infinie et le programme plantera. Le case de base est donc la condition de fin de la fonction récursive.

Le cas de propagation représente l'ensemble des lignes de code où aura lieu la récursivité. Il s'agit, en clair, du bloc de code où la fonction fera à nouveau appel à elle-même.

Écrivons de nouveau la fonction factorial mais cette fois de manière récursive.

function factorial(x) {
  // This is the base case.
  if (x === 0) return 1;
  // This is the recursive one.
  else return x * factorial(x - 1);
}

factorial(5); // output : 120

Notre cas de base déclare que si x est égal à 0, nous retournons la valeur 1. Cette fonction factorial va donc s'arrêter au moment où x atteindra la valeur 0. Pour toute autre valeur positive de x, nous retournons, le produit de x et de factorielle x.

Décomposons factorial(5) pas à pas, pour bien comprendre le mécanisme de la récursivité.

factorial(5) = 5 * factorial(4);
factorial(4) = 4 * factorial(3);
factorial(3) = 3 * factorial(2);
factorial(2) = 2 * factorial(1);
factorial(1) = 1 * factorial(0);
factorial(0) = 1;
// Donc :
// factorial(1) = 1 * 1;
// factorial(2) = 2 * 1 * 1;
// factorial(3) = 3 * 2 * 1 * 1;
// factorial(4) = 4 * 3 * 2 * 1 * 1;
// factorial(5) = 5 * 4 * 3 * 2 * 1 * 1 = 120

Penser récursif

Mettre en place des fonctions qui utilisent le principe de la récursivité n'est absolument pas inné. Cependant, il vous permettra d'obtenir des fonctions plus élégantes découpées en de plus petites instances d'elles-même. Mais il faut nécessairement de la pratique !

Ma principale recommandation est de penser en premier lieu au cas de base. C'est grâce à cette condition de fin essentielle que votre programme ne plantera pas et ne tournera pas de manière infinie. Prenez une feuille, posez cette condition et essayez systématiquement de réduire votre problème à une solution simple. Vous pouvez continuer cette réflexion autour de cet article de Santosh Rajan par exemple.

Améliorer l’échange autour de la performance web

Copyright : O'Reilly Conferences

La première keynote à laquelle j’ai assisté lors de la conférence Velocity est celle d’Aaron Rudger. Aaron Rudger est un technicien possédant une longue expérience en tant que directeur marketing et produit senior chez Keynote Systems en Californie. Son principal objectif, en tant que professionnel référent dans son domaine, est d’établir un univers de développement performant autour des solutions de monitoring de son entreprise sans pour autant déprécier les désirs de ses clients.

Maximize the return of your digital investments est avant tout une prise de connaissance sur le monde dans lequel nous évoluons actuellement, notamment en matière de performance web. La principale question soulevée est celle de la communication entre les équipes marketing et les équipes de développement.

Comme le souligne Aaron Rudger tout au long de son discours, il peut être parfois difficile de faire comprendre aux équipes marketing et commerciales l’enjeu de la performance pour les utilisateurs d’un site internet ou d’une application web. Pourquoi ?  Parce que les clients en veulent toujours plus : plus de publicités digitales, plus de connexions avec les réseaux sociaux, dont le nombre ne cesse d’accroître par ailleurs, plus de pixels captant le comportement des utilisateurs, des images de plus en plus grandes et donc de plus en plus lourdes, etc.. Et bien évidemment, la plupart de ces contenus proviennent de plateformes complètement hors de notre portée, et ne rendent pas nécessairement l’expérience utilisateur satisfaisante.

Selon une étude de la société Forrester réalisée en 2012, près de 32% des acteurs du marketing – directeur marketing, assistant marketing, planner stratégique, media planner, chargé d’études, directeur d’études, manager de la marque, responsable marketing digital, chef de publicité, directeur de clientèle, etc. – pensent que leur département technologique entrave à la réussite budgétaire de leur entreprise. En 2014, Aaron Rudger nous informe que ce nombre est passé à près de 43%. D’après lui, cette croissance souligne simplement que la manière dont le marketing et celle dont les équipes de développement pensent à la performance est de plus en plus divergente.

Parler de temps de connexion inférieur à un certain nombre de secondes pour une page web ne signifie pas grand chose de concret pour tous les « marketeux ». En réalité, c’est toute la notion d’analytics qui n’a pas de grande valeur à leurs yeux. Selon eux, les indicateurs clés de performance d’un bon produit, les Key Performance Indicators, sont l’engagement, la fidélité et la croissance. Il faut donc savoir construire un discours qui dégagera naturellement toutes ces notions dans le contexte de l’entreprise. Parler de l’amélioration du start render en disant par exemple que celui-ci augmentera l’engagement des utilisateurs à terme, et donc aura un impact positif sur les revenus, est une façon de convaincre les équipes marketing de l’intérêt d’un tel projet, qui ne leur semblerait que technique à première vue.

Le principal conseil d’Aaron Rudger serait donc d’élever la conversation pour convaincre les équipes marketing. Il faudrait ainsi, en toutes circonstances, certes mentionner les aspects techniques de nos futurs développements, mais surtout démontrer l’impact final sur la réussite de l’entreprise grâce à la performance technique. Changer sa manière de dialoguer et adopter un discours selon son interlocuteur peut directement jouer en notre faveur. « Create your own sense of ownership around performance that’s driving business impact in your organization. » Aaron Rudger nous propose d’ailleurs un article, Do you speak the same language as your business ?, pour poursuivre les réflexions autour de cette problématique. Vous pouvez également écouter cette keynote grâce à la vidéo ci-dessous.