Best functional programming practices for validating inputs and using scoping?

fuzzybabybunny

Moderator<br>Digital & Video Cameras
Moderator
Jan 2, 2006
10,455
35
91
This is javascript:

Here, none of the function arguments are validated and the "returnShippingCost" function calls the "returnItemWeight" function due to the benefit of scoping.

Code:
// sample orderFormContents:

var myOrder = {
  customerInfo: {
    fname: "Sdfsd",
    lname: "sadfsd"
  },
  shippingAddress: {
    zipcode: 55555
  },
  items: [
    {
      sku: "343rsdf",
      qty: 4
    },{
      sku: "dsfsad",
      qty: 1
    }
  ]
};

var returnItemWeight = function(sku){
  // look up the item via sku and return the weight
};

var returnShippingCost = function(orderFormContents){
  var zipcode = orderFormContents.shippingAddress.zipcode;
  var shippingCost;
  var weight = 0;
  for(index in orderFormContents.items){
    weight += returnItemWeight(orderFormContents.items[index].sku);
  };
  //something that calculates and returns the shipping cost from the weight and zipcode
};

This is the simple way of making the function, but how important is it to:

1. First validate all inputs that go into the function?

2. Here I actually sent the "returnItemWeight" function as an argument into my second function. I could have relied on scoping but I'm explicitly sending the function in as an argument. Is it good practice to not rely on scoping when using a function defined outside the scope of the current function?

Code:
var returnItemWeight = function(sku){
  if (sku && typeof sku === "string"){
    // look up the item via sku and return the weight
  } else {
    // something that handles the error
  };
};

var returnShippingCost = function(orderFormContents, itemWeightFunction){
  // validate typeof and the very existence of values and keys and nested values 
  if (orderFormContents && typeof orderFormContents === "object" && orderFormContents.shippingAddress && orderFormContents.shippingAddress.zipcode && orderFormContents.items)
    var zipcode = orderFormContents.shippingAddress.zipcode;
    var shippingCost;
    var weight = 0;
    for(index in orderFormContents.items){
      weight += itemWeightFunction(orderFormContents.items[index].sku);
    };
    // do something that calculates and returns shipping cost based on weight and zipcode
  } else {
    // something that handles the various errors (no orderFormContents? no shippingAddress? no zipcode? no items?)
  };

};

returnShippingCost(myOrder, returnItemWeight);

The second example is much more robust, but it sure is a lot more code (I haven't even done the error handling).

But I've heard that it's good practice to always first check the arguments and have functions ONLY use things that have explicitly been fed into it via the arguments (including other functions)?
 
Last edited:

Gryz

Golden Member
Aug 28, 2010
1,551
204
106
Functional programming is something else completely. :)

Yes, it is always good practice to check your inputs before you use them. And better make the checks as robust as you can think of. Because Murphy's Law will make sure that there will always be someone who types in stuff you did not expect at all. Result is unexpected behaviour, wrong behaviour or just simply crashing code.

And when you deal with potentially hostile users (like on a website) you better make sure you do your input checking right. Because you might run into users who will do their utmost best to find some combination of input that will allow them to hack your website.

Imho it is best to do those checks asap, right after you read/receive the input. Make that a habit. There are 2 benefits: 1) you are less likely to forget to check input, and 2) when you do it always at the input, you are less likely that you do the same check twice or multiple times.
 

fuzzybabybunny

Moderator<br>Digital & Video Cameras
Moderator
Jan 2, 2006
10,455
35
91
Functional programming is something else completely. :)

Yes, it is always good practice to check your inputs before you use them. And better make the checks as robust as you can think of. Because Murphy's Law will make sure that there will always be someone who types in stuff you did not expect at all. Result is unexpected behaviour, wrong behaviour or just simply crashing code.

And when you deal with potentially hostile users (like on a website) you better make sure you do your input checking right. Because you might run into users who will do their utmost best to find some combination of input that will allow them to hack your website.

Imho it is best to do those checks asap, right after you read/receive the input. Make that a habit. There are 2 benefits: 1) you are less likely to forget to check input, and 2) when you do it always at the input, you are less likely that you do the same check twice or multiple times.
I see. In the case of my code example,

1. Am I even going about the checks right? There could be so many little things to check for...

2. Is it common for the first line of a function definition to be a massive if-statement that checks the inputs?

3. Is there some kind of standard boilerplate code and stuff that I should always be checking for?

4. Should I be writing a global function called check() or something that I can reuse over and over again each time I write a function? It would check inputs and do error handling.
 

Cogman

Lifer
Sep 19, 2000
10,286
147
106
I see. In the case of my code example,

1. Am I even going about the checks right? There could be so many little things to check for...

2. Is it common for the first line of a function definition to be a massive if-statement that checks the inputs?

3. Is there some kind of standard boilerplate code and stuff that I should always be checking for?

4. Should I be writing a global function called check() or something that I can reuse over and over again each time I write a function? It would check inputs and do error handling.

My preference for validation is to have a whole bunch of tiny validation functions and then to compose those together when doing final validation checks. The benefits here are that it is easier to do unit tests on these functions. It is easy to pull them out and reuse them where you need them. And it makes it easy to know exactly what is being validated and when (if you use good validation method names.)

If I were to do this, I would probably cook something up that looks a little like this

Code:
function Validation(message, level) {
  this.message = message;
  this.level = level;
}

Validation.prototype.Level = {
  OK: 0,
  WARN: 1,
  INVALID: 2
};

const VALID = new Validation('OK', Validation.Level.OK);

function warn(message) {
  return new Validation(message, Validation.Level.WARN);
}

function error(message) {
  return new Validation(message, Validation.Level.INVALID);
}

function ok(message) {
  return new Validation(message, Validation.Level.OK);
}

function isPositive(val) {
  if (val.units > 0)
    return VALID;
  return error('Positive units required!');
}

function hasAmountSet(val) {
  if (val.amount !== undefined)
    return VALID;
  return error('Amount must be set!');
}

const VALIDATORS = [isPositive, hasAmountSet];

function validateValue(val) {
  for (let i = 0; i < VALIDATORS.length ++i) {
    validation = VALIDATORS[i](val);
    if (validation.level >= Validation.Level.INVALID)
      console.log(validation.message);
  }
}

(Of course spitting things out into files, etc. Also, this is using some es6 stuff.)
 

Dissipate

Diamond Member
Jan 17, 2004
6,815
0
0
My preference for validation is to have a whole bunch of tiny validation functions and then to compose those together when doing final validation checks. The benefits here are that it is easier to do unit tests on these functions. It is easy to pull them out and reuse them where you need them. And it makes it easy to know exactly what is being validated and when (if you use good validation method names.)

If I were to do this, I would probably cook something up that looks a little like this

Code:
function Validation(message, level) {
  this.message = message;
  this.level = level;
}

Validation.prototype.Level = {
  OK: 0,
  WARN: 1,
  INVALID: 2
};

const VALID = new Validation('OK', Validation.Level.OK);

function warn(message) {
  return new Validation(message, Validation.Level.WARN);
}

function error(message) {
  return new Validation(message, Validation.Level.INVALID);
}

function ok(message) {
  return new Validation(message, Validation.Level.OK);
}

function isPositive(val) {
  if (val.units > 0)
    return VALID;
  return error('Positive units required!');
}

function hasAmountSet(val) {
  if (val.amount !== undefined)
    return VALID;
  return error('Amount must be set!');
}

const VALIDATORS = [isPositive, hasAmountSet];

function validateValue(val) {
  for (let i = 0; i < VALIDATORS.length ++i) {
    validation = VALIDATORS[i](val);
    if (validation.level >= Validation.Level.INVALID)
      console.log(validation.message);
  }
}

(Of course spitting things out into files, etc. Also, this is using some es6 stuff.)

I agree that this is a good technique, especially because it allows you to easily add validation functions later, if needed.

Another technique that I have been using is contracts. Contracts can be a great way to get the same functionality as assertions but with less boilerplate. You apply contracts to functions to do type checking, or check for other things. Looks like there is a contracts library for JS: https://www.npmjs.com/package/contracts-js.