Previously we've talked a bit about the utility of FP and some of its core tenets.
In this post we're going to talk about how to identify patterns for potential cleanup in imperative code, on our path to tacit functional code.
The bulk of the rewriting is in the simplification of the underlying patterns at play in someone's code. Identify any of the following as candidates for clean-up and refactoring:
&&
s. Likely you should use something like ramda's pathOr
function to both safely access nested properties as well as provide a fallback in the case of missing properties.map
instead, as dealing with discrete values is much nicer than being in the dark.try ... catch
pattern and used it to to swallow errors silently. This is almost always a mistake.Promises
and async / await
are okay solutions for managing asynchrony. All too often they are misused or only written for the ideal case. I am a huge proponent of using fluture to model asynchrony, as it is lazy, monadic, cancellable and explicit about how things should work, especially error handling.this
makes a function impure.Let's say you have to deal with some code which does something like the following:
const saveData = (key, value) => {
window.localStorage.setItem(key, value)
}
If you're familiar with your basic JS environments, window
is tied to the browser but doesn't exist on the server / in node without a shim — so this function is unsafe.
However, look at how we can make this function be identical in functionality but also perfectly safe:
const saveDataWithStorage = storage => (key, value) => {
storage.setItem(key, value)
}
// or with ramda, you can have automatic currying, which is probably what you want
// import {curry} from 'ramda'
// saveDataWithStorage = curry((storage, key, value) => {})
// ostensibly this could also be in the body of the function itself
if (typeof window !== 'undefined') {
const saveData = saveDataWithStorage(window.localStorage.bind(window.localStorage)
}
By closuring the global function we're making use of, we can safely use that function in more places, and we have more explicit definition around what our dependencies / requirements are. Another nice free benefit of this pattern is that you can easily inject shims for testing purposes, so maintaining 100% unit test coverage is pretty easy.