Got something to add? Send a PR!
TODO: Add rationale
Keep the contents of try/catch blocks to a minimum.
Bad Example
try {
const config = yaml.safeLoad(fs.readFileSync(path.join(process.cwd(), configFile), 'utf8'));
const { projectName, scanPaths } = config;
const resolvedScanPaths = [];
scanPaths.forEach(scanPath => {
resolvedScanPaths.push(path.join(__dirname, scanPath));
});
...
...
27 lines later
...
} catch (e) {
console.error('Could not read config file, assuming defaults.');
}
Prefer
let config;
try {
config = fs.readFileSync(path.join(process.cwd(), configFile), 'utf8'));
} catch (e) {
console.error('Could not read config file, assuming defaults.');
}
There's lots of things could throw inside our original try block. We may accidentally silence and ignore unrelated errors.
(e.g. Maybe the config file was found, but scanPaths
wasn't specified - so scanPaths.forEach
throws, but we silenced it! Uh oh!)
Be specific when catching an error. Rethrow all other errors.
Bad Example
try {
result = divideNumbers(3, 0);
} catch (e) {
console.error("You can't divide by zero!");
}
Prefer
try {
result = divideNumbers(3, 0);
} catch (e) {
if (e instanceof DivideByZeroError) {
console.error("You can't divide by zero!");
} else {
throw e;
}
}
Lots of things could throw!
The message displayed to users or recovery logic inside the catch block may only apply to a certain type of error. But the catch block may be triggered with more errors types than you expect! (e.g. Someone accidentally renames the divideNumbers function, and now we're also catching a ReferenceError
!)
Avoid "catch all" blocks that gobble up errors we didn't intend to catch.
More reading: https://gist.github.com/jehugaleahsa/f3c43d41e68a6b4bc73d2d6cbaee876a#within-a-limited-scope
TODO: Add rationale
TODO: Add rationale
something something avoid side effects / global state
TODO: Add rationale
When throwing a new error from inside a try/catch block, preserve the stack from the caught error.
Bad Example
try {
config = readFileSync(configFilePath, 'utf8');
} catch (e) {
throw new Error("Could not read config file - ensure this file exists!");
}
Prefer
try {
config = readFileSync(configFilePath, 'utf8');
} catch (e) {
// Print both stack traces
throw new MultiError(["Could not read config file - ensure this file exists!", e]);
}
We don't want to gobble up the stack trace from the caught error as it contains potentially useful information.
In our example, the original stack trace will show the location on disk that we tried to read the config file from. Throwing this information away makes debugging harder.
JavaScript libraries to help:
TODO: Add rationale
TODO: Add rationale
Further Reading / Prior Art
TODO: Add rationale
TODO: Add rationale
-
Further Reading / Prior Art