Julien Philippon

Plusieurs façons de faire une chose simple

L’idée m’est venue d’un de mes collègues qui avait besoin de faire une fonction qui doit retourner une valeur avec un seuil maximum de 10 (En vrai c’était 5000, mais j’avais + d’idées avec 10 😄). En gros, si le chiffre est entre 0 et 9, on retourne le chiffre, si le chiffre est 10 ou au dessus on retourne toujours 10. Il avait utilisé une ternaire et cherchais à optimiser pour ne pas répéter la valeur (deux fois nb et 10 sur a même ligne) :

const fn = (nb) => nb < 10 : nb : 10

Après une petite recherche, nous avons trouvé une façon plus courte (un caractère de moins 😄) :

const fn = (nb) => Math.min(nb, 10)

Qui peut être encore plus courte si on récupère la fonction min dans une variable :

const min = Math.min
const fn = (nb) => min(nb, 10)

À partir de là, je me suis dit qu’il y a probablement plein de bonnes (et mauvaises) façons de faire cela. Je me suis amusé à en lister quelques-unes… Et je pense avoir exploité qu’une partie des possibilités.

Vous pourrez trouver (et contribuer si le cœur vous en dit) toutes ces méthodes sur github : https://github.com/apoutchika/many-ways-of-doing

A noter que le test unitaire fait ces quatre tests pour valider cette fonction :

fn(0) === 0
fn(5) === 5
fn(10) === 10
fn(15) === 10

La façon classique, sans ternaire :

module.exports.classic = (nb) => {
  if (nb < 11) {
    return nb
  }

  return 10
}

La même fonction, mais inversé :

module.exports.classicInversed = (nb) => {
  if (nb > 10) {
    return 10
  }

  return nb
}

(Je vous passe les mêmes avec <= et >=)

Fan de cache :

const cache = new Map()
module.exports.cacheLove = (nb) => {
  if (cache.get(nb)) {
    return nb
  }

  // Choisir la méthode de votre choix :-)
  const val = Math.min(nb, 10)

  cache.set(nb, val)
  return cache.get(nb)
}

Fan de cache, refactorisé :

const cache2 = new Map()
module.exports.cacheLoveRefactored = (nb) => {
  if (!cache2.get(nb)) {
    cache2.set(nb, Math.min(nb, 10))
  }

  return cache2.get(nb)
}

Avec une API

Oui, il y a des API pour tout…

const axios = require('axios')

module.exports.useExternalAPI = (nb) =>
  axios
    .get('https://api.mathjs.org/v4/', {
      params: {
        expr: `min(10, ${nb})`,
      },
    })
    .then((res) => res.data)

Avec un module externe :

const _ = require('lodash')

module.exports.withExternalModule = (nb) => _.min([10, nb])

Avec un tableau :

module.exports.withArray = (nb) => {
  const res = new Array(10)
    .fill()
    .map((value, key) => key)
    .find((value, key) => key === nb)

  if (res === 0) {
    return 0
  }

  return res || 10
}

Le.a tricheur.se :

Ben oui, en se basant sur les quatre tests… Ça passe !

module.exports.theCheater = (nb) => {
  if (nb === 0) {
    return 0
  }

  if (nb === 5) {
    return 5
  }

  if (nb === 10) {
    return 10
  }

  if (nb === 15) {
    return 10
  }
}

Les inconscients

Un peu dans la même veine que le.a tricheur.se, sauf que là c’est plutôt une ignorance sur le fait que ça peut devenir verbeux, moins performant ou même ne plus marcher si on augmente la limite…

Celui/Celle qui prépare le terrain

const prep = {
  0: 0,
  1: 1,
  2: 2,
  3: 3,
  4: 4,
  5: 5,
  6: 6,
  7: 7,
  8: 8,
  9: 9,
}

module.exports.prepared = (nb) => (prep[nb] !== undefined ? prep[nb] : 10)

Avec une petite regex ?

module.exports.regex = (nb) => (nb.toString().match(/^\d$/) ? nb : 10)

Switch / Case

module.exports.unconscious1 = (nb) => {
  switch (nb) {
    case 0:
      return 0
    case 1:
      return 1
    case 2:
      return 2
    case 3:
      return 3
    case 4:
      return 4
    case 5:
      return 5
    case 6:
      return 6
    case 7:
      return 7
    case 8:
      return 8
    case 9:
      return 9
    default:
      return 10
  }
}

Boucle For

module.exports.unconscious2 = (nb) => {
  for (let i = 0; i <= 10; i += 1) {
    if (i === nb) {
      return i
    }
  }

  return 10
}

Boucle Do While

module.exports.unconscious3 = (nb) => {
  let i = 0
  do {
    if (i === nb) {
      return i
    }
    i += 1
  } while (i <= 10)

  return 10
}

Le.a malin.e

module.exports.unconscious4 = (nb) => (nb.toString().length === 1 ? nb : 10)

Pour mettre fin à ma réflexion du jour

Je me demande si les possibilités sont infinies…

Pour une simple fonction comme celle-ci nous avons autant de façons de faire, alors je vous laisse imaginer le nombre de possibilités pour réaliser un projet entier… C’est là toute la difficulté qu’un.e développeur.se peut avoir lorsqu’il/elle rejoint un projet qu’il/elle ne connait pas…