Fail fast, validate arguments using a dedicated library

One Paragraph Explainer

We all know how checking arguments and failing fast is important to avoid hidden bugs (see anti-pattern code example below). If not, read about explicit programming and defensive programming. In reality, we tend to avoid it due to the annoyance of coding it (e.g. think of validating hierarchical JSON object with fields like email and dates) – libraries like Joi and Validator turn this tedious task into a breeze.

Wikipedia: Defensive Programming

Defensive programming is an approach to improve software and source code, in terms of General quality – reducing the number of software bugs and problems. Making the source code comprehensible – the source code should be readable and understandable so it is approved in a code audit. Making the software behave in a predictable manner despite unexpected inputs or user actions.

Code example: validating complex JSON input using ‘Joi’

  1. var memberSchema = Joi.object().keys({
  2. password: Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/),
  3. birthyear: Joi.number().integer().min(1900).max(2013),
  4. email: Joi.string().email()
  5. });
  6. function addNewMember(newMember) {
  7. // assertions come first
  8. Joi.assert(newMember, memberSchema); //throws if validation fails
  9. // other logic here
  10. }

Anti-pattern: no validation yields nasty bugs

Javascript

  1. // if the discount is positive let's then redirect the user to print his discount coupons
  2. function redirectToPrintDiscount(httpResponse, member, discount) {
  3. if (discount != 0) {
  4. httpResponse.redirect(`/discountPrintView/${member.id}`);
  5. }
  6. }
  7. redirectToPrintDiscount(httpResponse, someMember);
  8. // forgot to pass the parameter discount, why the heck was the user redirected to the discount screen?

Typescript

  1. // if the discount is positive let's then redirect the user to print his discount coupons
  2. function redirectToPrintDiscount(httpResponse: Response, member: Member, discount: number) {
  3. if (discount != 0) {
  4. httpResponse.redirect(`/discountPrintView/${member.id}`);
  5. }
  6. }
  7. redirectToPrintDiscount(httpResponse, someMember, -12);
  8. // We passed a negative parameter discount, why the heck was the user redirected to the discount screen?

Blog Quote: “You should throw these errors immediately”

From the blog: Joyent

A degenerate case is where someone calls an asynchronous function but doesn’t pass a callback. You should throw these errors immediately since the program is broken and the best chance of debugging it involves getting at least a stack trace and ideally a core file at the point of the error. To do this, we recommend validating the types of all arguments at the start of the function.