Fatal Error

highway to hell

Part 1: Theory

Contents

  • Definition of Error 
  • Error types
  • Where it comes from
  • How do we go with this
  • Exceptions
  • Working examples
  • Conclusion

Definition of Error: in our life

something goes wrong

something doesn't go the way expected

something does strange things

something comes with things you don't even know what to do with

you do something wrong, so consequently it does everything from above

you have got issues with DNA :)

Definition of Error: In Programming World

error resulting from bad code in some program involved in producing 

the erroneous result

unexpected conditions that are not part of the normal operation of a program

bug in a program that causes it to operate incorrectly, but not to terminate abnormally (or crash).

Operation Errors

Programmer Errors

Error Types

Run-time problems experienced by correctly-written programs.

 

These are not bugs in the program.

 

Usually problems with external things:

- system itself  

- system's configuration

- server hardware

- network 

Bugs in the program.

 

Things that can always be avoided by changing the code.

 

They can never be handled properly (since by definition the code in question is broken)

Where it comes from

- typo

​- invalidated data

- incompetence

- carelessness

- unsuitable system (OS, language, database, module etc. )

- overconfidence

- superstition

- corrupted library / service / module

- external system problems

Where it comes from: typo

function sayHello(name) {
    var messageHello = 'Hello, ' + name;
    console.log(messageEhllo);
}

sayHello('James Heatfield');
//ReferenceError: messageEhllo is not defined

Description:

Painkiller:

- configure IDE to handle typos (ex. 'strict mode' in Java Script)

- develop and follow naming convention

- be careful and practise 

Where it comes from: invalidated data

Painkiller:

- validate incoming data 

Description:

- missing data validators

function displayName(personObject) {
    console.log(personObject.full_name);
}

displayName({}); //undefined
displayName();   //TypeError: Cannot read property 'full_name' of undefined
function displayName(personObject) {
    if(personObject && personObject.full_name) {
	console.log(personObject.full_name);	
    }
}

displayName({});        //
displayName();          //
displayName({full_name: 'James Heatfield'}); //James Heatfield

Where it comes from: incompetence

Description:

- junior developer

- new technology 

- you are involved in already working project

 

Painkiller:

- heaving team lead

- project documentation

- always think before you do something  

Where it comes from: carelessness

Description:

- bad code format/style

- missing comments

- incomprehensible variable and function declaration

- missing application structure

- etc.  

 

 

Painkiller:

- create a "blueprint" before you start

- follow code convention

- comment your code / create self-commented code

Where it comes from: unsuitable system

Description:

- slow server

- chose database is not compatible with requested tasks

- using OS is not compatible with an application

 

Painkiller:

- don't be afraid of new technologies 

- work on requirements and require full project description   

Where it comes from: overconfidence

Description:

- "that's not my bad"

- "I am pretty sure that my code is working fine"

- "you better check your computer as it's working fine on my side"

 

 

Painkiller:

- trust your team

- work with your team

- be a bit prejudiced against your code

Where it comes from: superstition

Description:

- "that's not my code, there is something with this system"

- "my compiler does this wrong"

 

Painkiller:

- compiler is your friend

- be a bit prejudiced against your code

Where it comes from: corrupted library / service / module

Description:

- module contains corrupted code

- a library is out of date

- service is not suitable with the current environment 

- etc.

 

Painkiller:

- think and check library before you use it

- check module requirements

- check if service is still supported

Where it comes from: external system problems

Description:

- out of memory

- power off

- disk corruption

- etc.

 

Painkiller:

- choose suitable service

- high-level server configuration

- correct error handling

How do we go with this: error handling patterns

How do we go with this: error handling patterns

- return a neutral value

var DEFAULT_GREETING = 'Hello';
var GREETING_PHRASES = ['good morning', 'good evening', 'howzit', 'sup'];

function sayHello(name) {
  var greeting = '';
  try {
    greeting = getGreetingPhrase(GREETING_PHRASES);
  } catch(err) {
    greeting = DEFAULT_GREETING;
  }
  
  console.log(greeting + ', ' + name);
}

function getGreetingPhrase(inputPhrases) {
  if(!(inputPhrases && inputPhrases.length)) {
    throw new Error('no greeting phrases provided');
  }
  return inputPhrases[Math.floor(Math.random()*inputPhrases.length)];
}

sayHello('James Heatfield');

//sup, James Heatfield

How do we go with this: error handling patterns

return a neutral value

var DEFAULT_GREETING = 'Hello';
var GREETING_PHRASES = ['good morning', 'good evening', 'howzit', 'sup'];

function sayHello(name) {
  var greeting = '';
  try {
    greeting = getGreetingPhrase();
  } catch(err) {
    greeting = DEFAULT_GREETING;
  }
  
  console.log(greeting + ', ' + name);
}

function getGreetingPhrase(inputPhrases) {
  if(!(inputPhrases && inputPhrases.length)) {
    throw new Error('no greeting phrases provided');
  }
  return inputPhrases[Math.floor(Math.random()*inputPhrases.length)];
}

sayHello('James Heatfield');

//Hello, James Heatfield

How do we go with this: error handling patterns

return a neutral value

How do we go with this: error handling patterns

- return a neutral value

- substitute the next piece of valid data

How do we go with this: error handling patterns

substitute the next piece of valid data

How do we go with this: error handling patterns

- return a neutral value

- substitute the next piece of valid data

- return the same answer as the previous time

How do we go with this: error handling patterns

return the same answer as the previous time

var previousResult = '00000';

function getData() {
  var output = '';

  try {
    output = getCharData();
    previousResult = output;
  } catch(err) {
    output = previousResult;
  }
  return output;
}
function getCharData() {
  var err = !(Math.random() >= 0.5); //error simulation
  if(err) {
    throw Error('no data gathered');
  }
  return generateChars();
}

function generateChars() {
  var output    = '';
  var letters   = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  var newChar   = '';
  var charIndex = 0;

  for( var i = 0; i < 5; i++ ) {
    charIndex = Math.floor(Math.random() * letters.length);
    newChar = letters.charAt(charIndex);
    output += newChar;
  }
  return output;
}
for(var i = 0; i < 7; i++) {
  console.log(getData());
}

//00000 -> error
//ZMr6q
//d9MFW
//d9MFW -> error
//N5yqs
//ESirp
//ESirp -> error

How do we go with this: error handling patterns

- return a neutral value

- substitute the next piece of valid data

- return the same answer as the previous time

- substitute the closest legal value

How do we go with this: error handling patterns

substitute the closest legal value

var SPEED_MIN = 0;
var SPEED_MAX = 150;

//inputSpeed from sensor
function getSpeed(inputSpeed) {
  if(inputSpeed < SPEED_MIN) {
    return SPEED_MIN;
  }

  if(inputSpeed > SPEED_MAX) {
    return SPEED_MAX;
  }

  return inputSpeed;
}

console.log(getSpeed(45));
console.log(getSpeed(-10));
console.log(getSpeed(260));
console.log(getSpeed(150));

//45
//0
//150
//150

How do we go with this: error handling patterns

- return a neutral value

- substitute the next piece of valid data

- return the same answer as the previous time

- substitute the closest legal value

- log a warning message to a file

How do we go with this: error handling patterns

log a warning message to a file

var SPEED_MIN = 0;
var SPEED_MAX = 150;

//inputSpeed from sensor
function getSpeed(inputSpeed) {
  if(inputSpeed < SPEED_MIN || inputSpeed > SPEED_MAX) {
    log(new Error('invalid speed value'));
  }
  return inputSpeed;
}

function log(errorMessage) {
  console.log(new Date() + ': ' + errorMessage);
}

console.log(getSpeed(45));
console.log(getSpeed(-10));
console.log(getSpeed(260));

//45

//Wed Nov 04 2015 01:16:33 GMT+0200 (EET): Error: invalid speed value
//-10

//Wed Nov 04 2015 01:16:33 GMT+0200 (EET): Error: invalid speed value
//260

How do we go with this: error handling patterns

- return a neutral value

- substitute the next piece of valid data

- return the same answer as the previous time

- substitute the closest legal value

- log a warning message to a file

- return an error code

How do we go with this: error handling patterns

return an error code

var SPEED_MIN = 0;
var SPEED_MAX = 150;

//inputSpeed from sensor
function getSpeed(inputSpeed) {
  if(inputSpeed < SPEED_MIN || inputSpeed > SPEED_MAX) {
    throw { code: 100, message: 'invalid speed value' };
  }
  return inputSpeed;
}

try {
  getSpeed(-10);
} catch(err) {
  //doSomething
}

//{ code: 100, message: 'invalid speed value' }

How do we go with this: error handling patterns

- return a neutral value

- substitute the next piece of valid data

- return the same answer as the previous time

- substitute the closest legal value

- log a warning message to a file

- return an error code

- call an error-processing routing

How do we go with this: error handling patterns

call an error-processing routing

var SPEED_MIN = 0;
var SPEED_MAX = 150;

//inputSpeed from sensor
function getSpeed(inputSpeed) {
  if(isNaN(inputSpeed)) {
    throw {message: 'invalid speed value'};
  }

  if(inputSpeed < SPEED_MIN) {
    throw {code: 100, message: 'invalid speed value'};
  }

  if(inputSpeed > SPEED_MAX) {
    throw {code: 200, message: 'invalid speed value'};
  }

  return inputSpeed;
}
function errorHandler(err) {
  switch(err.code) {
    case 100:
      console.log('Error 100');
      break;
    case 200:
      console.log('Error 200');
      break;
    default:
      console.log('Oops');
      break;
  }
}
try {
  getSpeed('-10');
} catch(err) {
  errorHandler(err);
}
//Error 100
try {
  getSpeed('360');
} catch(err) {
  errorHandler(err);
}
//Error 200
try {
  getSpeed('doh');
} catch(err) {
  errorHandler(err);
}
//Oops

How do we go with this: error handling patterns

- return a neutral value

- substitute the next piece of valid data

- return the same answer as the previous time

- substitute the closest legal value

- log a warning message to a file

- return an error code

- call an error-processing routing

- display an error message

How do we go with this: error handling patterns

display an error message


function getGreetingPhrase() {
  var PHRASES = ['Good Morning', 'Sup', 'Hello'];
  var err = !(Math.random() >= 0.5); //error simulation
  if(err) {
    console.log('Error:  Failed to generate greeting phrase');
    return false;
  }
  return PHRASES[Math.floor(Math.random()*PHRASES.length)];
}

function getRandomName() {
  var NAMES = ['James', 'John', 'Doug'];
  var err = !(Math.random() >= 0.5); //error simulation
  if(err) {
    console.log('Error:  Failed to get random name');
    return false;
  }
  return NAMES[Math.floor(Math.random()*NAMES.length)];
}
function getContactFullPhrase(greeting, name) {
  var err = !(Math.random() >= 0.5); //error simulation
  if(err) {
    console.log('Error:  Failed to concat full phrase');
    return false;
  }
  return greeting + ', ' + name;
}

function sayHello() {
  var full_phrase = '';
  var name        = getRandomName();
  var greeting    = getGreetingPhrase();

  if(name && greeting) {
    full_phrase = getContactFullPhrase(greeting, name);
  }

  if(full_phrase) {
    console.log(full_phrase);
  }
}

sayHello();

//Error:  Failed to generate greeting phrase
//Error:  Failed to get random name
//Hello, John

How do we go with this: error handling patterns

display an error message

How do we go with this: error handling patterns

- return a neutral value

- substitute the next piece of valid data

- return the same answer as the previous time

- substitute the closest legal value

- log a warning message to a file

- return an error code

- call an error-processing routing

- display an error message

- handle the error locally

How do we go with this: error handling patterns

handle the error locally

function getGreetingPhrase() {
  var PHRASES = ['Good Morning', 'Sup', 'Hello'];
  var err = !(Math.random() >= 0.5); //error simulation
  if(err) {
    console.log('ERROR: ', err.message || 'Oops');
  }
  return PHRASES[Math.floor(Math.random()*PHRASES.length)];
}

function getRandomName() {
  var NAMES = ['James', 'John', 'Doug'];
  var err = !(Math.random() >= 0.5); //error simulation
  if(err) {
    console.log('ANOTHER WAY OF HANDLING: ', err.code || '100');
  }
  return NAMES[Math.floor(Math.random()*NAMES.length)];
}

getGreetingPhrase();
getRandomName();

//ERROR:  Oops
//ANOTHER WAY OF HANDLING:  100

How do we go with this: error handling patterns

- return a neutral value

- substitute the next piece of valid data

- return the same answer as the previous time

- substitute the closest legal value

- log a warning message to a file

- return an error code

- call an error-processing routing

- display an error message

- handle the error locally

- shut down the system

How do we go with this: error handling patterns

shut down the system

function getGreetingPhrase() {
  var PHRASES = ['Good Morning', 'Sup', 'Hello'];
  var err = !(Math.random() >= 0.5); //error simulation
  if(err) {
    process.exit();
  }
  return PHRASES[Math.floor(Math.random()*PHRASES.length)];
}

getGreetingPhrase();

How do we go with this: error handling patterns

Think before you choose the way of handling errors because not all of them may be suitable for your application.

It's better to shutdown a system in case of error if you work with medical equipment (for example) and at the same time there no reason to spend much time on creating a strong strategy when you plan to develop some new version of tic-tac-toe game. 

Exceptions: definition 

Anomalous or exceptional conditions requiring special processing - often changing the normal flow of program execution.

Something that doesn't go expectantly. 

Exceptions: work flow

- throw

- callback

- even emitter

Exceptions: Throw

function lift(direction) {
  var DIRECTION_UP 	= 'up';
  var DIRECTION_DOWN 	= 'down';

  switch(direction) {
    case DIRECTION_UP:
      //doSomething
      break;
    case DIRECTION_DOWN:
      //doSomething
      break;
    default:
      throw new Error('invalid direction');
  }
}

try {
  lift('toHell');
} catch(err) {
  console.log(err);
}

//[Error: invalid direction]

Exceptions: Callback

function lift(direction, callback) {
  var DIRECTION_UP 	= 'up';
  var DIRECTION_DOWN 	= 'down';

  switch(direction) {
    case DIRECTION_UP:
      callback(null, DIRECTION_UP);
      break;
    case DIRECTION_DOWN:
      callback(null, DIRECTION_DOWN);
      break;
    default:
      callback(new Error('invalid direction'), false);
  }
}


lift('toHell', function(err, result) {
  if(err) {
    //doSomethingWithError
  }
  //handle result
});

Exceptions: Event Emitter

var events        = require('events');
var eventEmitter  = new events.EventEmitter();

function handleErrors(err) {
  console.log('Oops, something went wrong!');
  console.log(err);
}

eventEmitter.on('appException', handleErrors);


function lift(direction) {
  var DIRECTION_UP 	= 'up';
  var DIRECTION_DOWN 	= 'down';

  switch(direction) {
    case DIRECTION_UP:
      //doSomething
      break;
    case DIRECTION_DOWN:
      //doSomething
      break;
    default:
      eventEmitter.emit('appException', new Error('invalid direction'));
  }
}

lift('toHell');

//Oops, something went wrong!
//[Error: invalid direction]

Exceptions: Notes

- try-catch doesn't work with asynchronous function

- in a callback flow error should be passed as a first argument

- event emitter way increases amount of dependencies between different code blocks or modules

Exceptions: async catch with promises

MyModel
    .findItem(searchQuery)
    .then(makeSomeMagic)
    .then(saveItem)
    .catch(function onError(err){   
        //handleError
    });

- easy to handle

- single work point

- all the internal unhandled errors will be thrown to the up level 'catch' 

Working Examples: NodeJs specification

var songService = {
    sing: function(lyrics) {
	showLyrics(lyrics);
    }
};

function showLyrics(lyrics) {
    console.log('LYRICS');
    console.log(lyrics);
}

module.exports = songService;
var lyrics = 'Take a look to the sky ' +
	     'Just before you die ' +
	     'Its the last time you will';

songService.sing(lyrics);


//LYRICS
//Take a look to the sky Just before you die Its the last time you will

Simple Working Function

Working Examples: NodeJs specification

var songService = {
    sing: function(lyrics) {
	showLyrics(lyrics);
    }
};

function showLyrics(lyrics) {
    console.log('LYRICS');
    console.log(lyrics);
}

module.exports = songService;
songService.sing();

//LYRICS
//undefined

Invalid Incoming Data

Working Examples: NodeJs specification

var songService = {
    sing: function(lyrics) {
	showLyrics(lyrics);
    }
};

function showLyrics(lyrics) {
    if(!lyrics) {
	throw new Error('no lyrics provided');
    }
	
    console.log('LYRICS');
    console.log(lyrics);
}

module.exports = songService;
try {
    songService.sing();
} catch(err) {
    console.log('ERROR');
    console.log(err);
} finally {
    console.log('Bye');
}

//ERROR
//[Error: no lyrics provided]
//Bye

Using Error object

Working Examples: NodeJs specification

var songService = {
    sing: function(lyrics) {
	showLyrics(lyrics);
    }
};

function showLyrics(lyrics) {
    if(!lyrics) {
	throw new exceptions.NoLyricsProvided();
    }
	
    console.log('LYRICS');
    console.log(lyrics);
}

module.exports = songService;
var exceptions = {
    NoLyricsProvided: function(errorMessage) {
	this.status 	= 404;
	this.message 	= errorMessage || 'no lyrics provided';
    }
};

module.exports = exceptions;
try {
    songService.sing();
} catch(err) {
    console.log('ERROR');
    console.log(err);
} finally {
    console.log('Bye');
}
//ERROR
//{ status: 404, message: 'no lyrics provided' }
//Bye

Using prepared exceptions

Working Examples: NodeJs specification

var exceptions = {
  UnknownError: function(errorMessage){
    this.status = 500;
    this.message = errorMessage || 'Oops, something went wrong';
  },

  NotFound: function(errorMessage){
    this.status = 404;
    this.message = errorMessage || 'not found';
  },

  NotAuthorized: function(errorMessage){
    this.status = 401;
    this.message = errorMessage || 'not authorized';
  },

  BadRequest: function(errorMessage){
    this.status = 400;
    this.message = errorMessage || 'input data is not valid';
  },

  AlreadyExist: function(errorMessage) {
    this.status = 409;
    this.message = errorMessage || 'already exist';
  }
};

module.exports = exceptions;
process.on('uncaughtException', function (err) {
  //doSomething
});

Working Examples: NodeJs specification

cluster.on('exit', function(worker) {
  //doSomething();
  cluster.fork();
});

System backup

Conclusion

create a "blueprint" before you start working on application

follow code convention

- be prejudiced against your code

choose the method of error handling according to tasks

 

Author:  Roman Sachenko

Email:    roman.sachenko@gmail.com

Skype:   roman.sachenko

Date:     Nov - 06 - 2015

fatal_error-highway_to_hell

By Roman Sachenko

fatal_error-highway_to_hell

  • 77
Loading comments...

More from Roman Sachenko