Inglorious 
Coderz 

Migliorare il codice con il currying

Oggi mi sono trovato davanti a un problema a prima vista molto semplice da realizzare, ma il cui risultato si è rivelato orribile e per niente ottimale. Il problema si descrive molto facilmente in linguaggio naturale "calcolare la differenza tra due liste A e B". Facile no? A prima vista sì, ma scendendo nel tecnico si è rivelato un po' più ostico del previsto, perché le mie due liste erano composte da oggetti, ognuno con più di un parametro e una chiave generata in modo randomico, quindi il problema andrebbe riformulato come "calcolare la differenza tra due liste di oggetti A e B basandosi su uno dei suoi parametri".

Parlando in JavaScript:

let nodesA = [
  { a: '1', b: '1' },
  { a: '2', b: '2' },
  { a: '3', b: '3' },
  { a: '4', b: '4' },
  { a: '5', b: '5' },
]
let nodesB = [
  { a: '1', b: '6' },
  { a: '2', b: '7' },
  { a: '3', b: '8' },
  { a: '6', b: '9' },
  { a: '7', b: '10' },
  { a: '8', b: '11' },
]

Come fare dunque a ottenere come risultato nodesA / nodesB, basandosi sul parametro a?

Questa è la prima versione a cui ho pensato:

let result = []
nodesB.forEach(nb => {
  let supportArr = []
  nodesA.forEach(na => {
    supportArr.push(na.a)
  })
  const notInNodesA = supportArr.indexOf(nb.a) === -1
  if (notInNodesA) {
    result.push(nb)
  }
})

È davvero brutta lo so, è quadratica quindi non ottimale ed è anche un po' scomoda da utilizzare, quindi ho dovuto per forza RIFATTORIZZARE. Inizialmente mi sono messo in testa di usare il filter e la map, ma non riuscivo a incastrare le cose come volevo (ottenevo o troppi dati o quelli che non mi interessavano) e nella mia ricerca mi sono imbattuto nel concetto di currying visto all'università, ma mai utilizzato in pratica. La definizione più semplice e immediata l'ho trovata su StackOverflow e poi con l'aiuto di un bel post trovato qua sono riuscito dopo un po' di tentativi ed errori a giungere a questo risultato.

Ho definito la funzione nodeCompare in questo modo:

const nodeCompare = otherArray => {
  return current => {
    return (
      otherArray.filter(other => {
        return other.a === current.a
      }).length === 0
    )
  }
}

e poi l'ho utilizzata così:

const difference = nodesB.filter(nodeCompare(nodesA))

Ho quindi applicato all'array nodesB un filtro che riceve come callback nodeCompare. La funzione nodeCompare riceve come parametro l'array nodesA che restituisce a sua volta il risultato di un filtro applicato sul nodesB, e se il risultato è vuoto o pieno mi restituirà true o false permettendo al primo filter lanciato di decidere se il valore è di mio interesse oppure no. Un salto di qualità notevole dopo la prima versione!

Spero con questo piccolo post di aver aiutato qualcuno o anche semplicemente spronato al REFACTORING, cosa che noi Inglorious Coders diciamo di fare sempre!

# Giosk