REQUEST A DEMO

Functional Javascript

javascript

Improving my own javascript style…

Here at Dovetail, developers are encouraged to keep themselves current with today’s coding practice.  Last year, I started studying functional coding to improve my javascript style, along with learning to write cleaner maintainable code.  The easiest way to explain is to take some code and we will begin to refactor it.  Here is a good example:

function findUserByName(name, data) {
    for (var i=0; i<data.length; i++) {
        if (data[i].name === name) { return data[i]; }
    }
    return undefined;
}

function removeUserByName(name, data) {
   for (var i=0; i<data.length; i++) {
         if (data[i].name === name) { 
             data.splice(i, 1);
         }
    }
    return data;
}


...

var users = [{name: 'John Doe'}, {name: 'Jane Doe'}, {name: 'Henry Smith'}];

findUserByName('John Doe', users); // returns {name: 'John Doe'}

... // Later in some code we want to remove the user
removeUserByName('John Doe', users);

Red Flags?

I hope as you read through this code you spotted all sorts of red flags.  I know there are other ways to iterate over the data instead of using a for loop, look past that for a sec.  This code works, you can copy and paste it into jsbin and see for yourself.  One obvious issue, splice is being used to remove a user from the array. Why is that an issue? Notice on the last line I didn’t need to use the returned data array? Splice is not an immutable function.  It actually modifies the data array I passed into the removeUserByName function.  It might not sound bad for this functionality, however, imagine I had some code that needed the users array to validate something entirely different and the array changed because of a function that called splice on it.  The rule of thumb is to never modify params that are passed into a function.  That function doesn’t own the data and therefore, should never modify it.  Instead, it should perform an action that returns a new object with the desired changes on it, or for short, be immutable.  What else can we do to refactor this? Well, for starters it’s not doing much and the two functions are taking up 15 lines of code.

Let’s see what we can do to make this smaller, cleaner, and immutable.

import R from 'ramda';

function findUserByName(name) {
  return R.find(R.propEq('name', name));
}

function removeUserByName(name) {
  return R.reject(R.propEq('name', name));
} 

var users = [{name: 'John Doe'}, {name: 'Jane Doe'}, {name: 'Henry Smith'}];

findUserByName('John Doe')(users) // returns {name: 'John Doe'}
var newUsers = removeUserByName('John Doe')(users);
console.log(users); // returns [{name: 'John Doe'}, {name: 'Jane Doe'}, {name: 'Henry Smith'}]

console.log(newUsers); // [{name:"Jane Doe"},{name:"Henry Smith"}]

In this code example, I’m using ramda for its curried functions.  Without getting too far into curry, it’s basically a way to set up a function that will return a function until all params are satisfied.  Once all parameters are satisfied, the function is called.  In the example of both functions here, R.find and R.reject are both expecting 2 parameters.  In these functions, I have only satisfied one and so a function is returned.  The second parameter expected is an array.

 findUsersByName

Let’s break down the findUsersByName function to better understand this.  The ramda function R.find is expecting the first parameter to be a function that returns a bool.  The second param is the array that is being iterated over.  We are passing in the name because we know it at the time of the call, however we might not know the array to iterate over just yet.  Above, I said the first param for find is a bool function, R.propEq is a bool returning function.  It checks if there is a key called ‘name’ with a value of the name we passed in because we basically configured it as R.propEq(‘name’, ‘John Doe’).

Basically the same as,

function (name, obj) { return obj.name === name); }

The above line of code is exactly the same as R.propEq with the exception it’s not curried.  If we curried that function it would work just the same, but isn’t it just easier to put R.propEq?  Hopefully I explained this without causing confusion.  Keep practicing this style of coding, it will make your code easier to maintain, reusable, and immutable.

 

Gary L. Cox, Jr.

%d bloggers like this: