Validation of the input parameter in caller or in the function called - josuamanuel/softwareDevelopmentPrinciples GitHub Wiki
This question has different angles:
- Separation of concerns:
The question arises as some developers tend to validate input parameters in each function. This could produce duplication of code. Let's see an example:
function average(listOfNumbers) { return divByLength(sum(listOfNumbers), listOfNumbers) }
function sum(listOfNumbers) { return listOfNumbers.reduce((acum,current) => acum+current,0) }
function divByLength( dividend, arrayToGetLength) { return dividend/arrayToGetLength.length }
What things could go wrong here: a) Caller sends an empty array. b) Caller sends something different to an array in the parameter: listOfNumbers
Let's examine each possible failure
a) Caller sends an empty array: This produces a division by Zero. So then should we put a validation in function avarage()? The answer is NO!!!! avarage is not concerned about doing the actual division. avarage is orquestrating actions. So... then... should we put the division validation by zero in divByLength? The answer is probably NOT either!!! at the end division is implemented by javascript and it already validates the value and returns NaN if divisor is 0. Let's see how it behaves:
avarage([]) //? NaN
It makes sense to me... why we need to duplicate validations (DUPLICATE CODE). avarage doesnt do division, it doesnt act on data, so why it needs to validate.
b) Caller sends something different to an array
Same as we said before average doesnt act on the array, so we should not put validation there.
sum uses listOfNumbers to invoke a method. If the type is not an array this will produce a "type error" exception. We have two options: • A radical one (not recommended): Define avarage contract to return: number, NaN, type error exception. • validate for typeof and return NaN if it is not an array. Then avarage contract: number, NaN (when parameters are not average-able.
- Ownership, boundaries:
Being able to separate components by encapsulating software mandates to define the interface of this bounderies. It means to define with detail the contract in terms of input, output and behaviours. The caller to a component could through anything and the component should respond according to its contract. Validation is done at entry point of the component. once we are inside the component we can assume data has been validated and we dont need to validate again. Of course doing that makes the internals of the component not reusable because these smalls internals assumes data is already validated and maybe this is not the case in the context where it is reused.