https://github.com/magicmark/programming-protips
programming protips for programmers
https://github.com/magicmark/programming-protips
Last synced: about 1 month ago
JSON representation
programming protips for programmers
- Host: GitHub
- URL: https://github.com/magicmark/programming-protips
- Owner: magicmark
- Created: 2020-12-03T20:35:11.000Z (over 5 years ago)
- Default Branch: main
- Last Pushed: 2021-01-20T19:20:19.000Z (over 5 years ago)
- Last Synced: 2026-01-15T04:29:00.329Z (3 months ago)
- Homepage:
- Size: 19.5 KB
- Stars: 2
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# 💡 Programming Protips
_Got something to add? [Send a PR](https://github.com/magicmark/engineering-protips/pulls)!_
### Limit the amount of logic on a single line of code
TODO: Add rationale
### Limit the amount of logic in a try/catch block
Keep the contents of try/catch blocks to a minimum.
**Bad Example**
```js
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**
```js
let config;
try {
config = fs.readFileSync(path.join(process.cwd(), configFile), 'utf8'));
} catch (e) {
console.error('Could not read config file, assuming defaults.');
}
```
#### Why?
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!)
### Limit what you catch
Be specific when catching an error. Rethrow all other errors.
**Bad Example**
```js
try {
result = divideNumbers(3, 0);
} catch (e) {
console.error("You can't divide by zero!");
}
```
**Prefer**
```js
try {
result = divideNumbers(3, 0);
} catch (e) {
if (e instanceof DivideByZeroError) {
console.error("You can't divide by zero!");
} else {
throw e;
}
}
```
#### Why?
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
### Use user-defined error codes
### DRY
TODO: Add rationale
### DRY
TODO: Add rationale
### Prefer writing pure functions where applicable
something something avoid side effects / global state
TODO: Add rationale
### Preserve prior stack traces when throwing errors
When throwing a new error from inside a try/catch block, preserve the stack from the caught error.
**Bad Example**
```js
try {
config = readFileSync(configFilePath, 'utf8');
} catch (e) {
throw new Error("Could not read config file - ensure this file exists!");
}
```
**Prefer**
```js
try {
config = readFileSync(configFilePath, 'utf8');
} catch (e) {
// Print both stack traces
throw new MultiError(["Could not read config file - ensure this file exists!", e]);
}
```
#### Why?
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:
- https://github.com/joyent/node-verror
- https://www.npmjs.com/package/aggregate-error
### Don't blindly copy/paste code
TODO: Add rationale
### Make custom error messages as useful as possible
TODO: Add rationale
**Further Reading / Prior Art**
- https://twitter.com/swyx/status/1329171738215686145
### Return early
TODO: Add rationale
### Don't try and outsmart the typechecker
TODO: Add rationale
### Read your stack trace. Scroll up.
### Don't pass functions too many arguments
- **Further Reading / Prior Art**
- http://wiki.c2.com/?TooManyParameters
### Don't pass functions the whole object