speculative nonfiction
Too many imports, eyes tired
There are too many imports in this React component file. I’m staring down like 50 lines of imports. External libraries (React, Lodash, etc…), our own internal libraries, components files, helpers, constants. The last bothers me the most because they feel like implementation details I want hidden away in these other components or helpers. So I’m looking at this statement inside a render() block:
const isSoldOut = this.props.statusType == SOLD_OUT;
And suddenly I’m reminded of what Kyle Simpson told me on twitter a couple weeks ago:
“in ‘functional programming,’ we love and embrace functions! functions everywhere!” – @getify
That’s it, that’s my out. We can refactor the equality expression into a function that represents data:
const isSoldOut = ({ status }) => status === SOLD_OUT;
We might find our code getting repetitive for computing different statuses:
const isSoldOut = ({ status }) => status === SOLD_OUT;
const isAvailable = ({ status }) => status !== UNAVAILABLE && status !== SOLD_OUT;
const isUnavailable = ({ status }) => status !== UNAVAILABLE;
// etc...
In which case we might find an indirection at a higher level that hides the implementation details of our equality expressions:
const getTicketStatusType = (ticketProps) => STATUS_TYPES_MAP[get(ticketProps, "status")];
STATUS_TYPES_MAP could implement an object hash where the equality expressions are values or our data functions.
This post almost became about mitigating import noise. But exploratory development while waxing with words wandered a bit. This is my day writing code in a nutshell – felicitous detours. Refactoring constants used for direct comparison into a reusable module. At the least those status constants can live in this new module. Nevertheless, the abstraction work yields other interesting propositions:
- Creating a reusable abstraction – which I know can be leveraged elsewhere
- De-cluttering render() which makes integration tests simpler, possibly unnecessary for some cases since logic can be independently unit tested
That last point is important. At least to me. Untidy render() blocks are hard to scan, debug, and test. The machinations for constructing and composing the things to render can happen in other places: above the component class definition, in class methods, or in a separate file. The first options is one I quite like because abstractions don’t have to be all that general. It’s great if they are localized to the component at hand.
Friday May 10, 2019