Eliminate an entire category of bugs with a few simple tools
How you can use a few simple static code analysis tools to avoid common programming bugs.
You’ve probably heard of ESLint, Prettier, and Flow/TypeScript. These are static code analysis tools that are wildly popular in the JavaScript ecosystem. I consider them all testing tools. Let’s take a look at each:
ESLint
ESLint is the pluggable linting utility for JavaScript. Linting is the process of analyzing code for potential errors without actually running the code. Consider this code:
if (!'serviceWorker' in navigator) { // the user's using an old browser :-( }
Do you spot the problem? If you do, that’s great! But don’t you think it’d be cool to not have to use your brain power to find and correct subtle bugs like this one? I do! Make a computer do as much of my work for me as possible, please and thank you. That’s what ESLint does for you.
Prettier
Prettier is the JavaScript code formatter. It’ll take your code however you write it, and reformat it in a way that’s consistent and legible every time. People often give me quizzical looks when I refer to Prettier as a testing tool. But check this out:
const a = false const b = false const c = true const d = a && b || c
What’s the value of d
here? Do you know the order of operations of those operators by heart? If you do, great! But do you trust that all the engineers on your team know them well enough to not introduce a bug when refactoring this?
Run that code through Prettier, and this is what you get:
const a = false const b = false const c = true const d = (a && b) || c
Even if you do know the order of operations, the extra parentheses—which Prettier automatically adds when you save the file—are quite helpful. And if you realize that’s not what you wanted, then you can add the parentheses yourself and Prettier will leave it that way (const d = a && (b || c)
).
This is one example of things Prettier does to make the intent of your code more obvious—freeing your brain to focus on harder problems.
Flow/TypeScript
These are static type checkers for JavaScript. A static type checker adds syntax to JavaScript to allow you to specify what data type a variable is. It can follow that variable through the code to make sure it’s being used properly. (No more x is not a function
.)
Can you spot the bug in this code?
function getFullName(user) { const {name: {first, middle, last}} = user return [first, middle, last].filter(Boolean).join('') } getFullName({first: 'Joe', middle: 'Bud', last: 'Matthews'})
Maybe you can, maybe you can’t. Maybe your coworkers can, maybe they can’t. In any case, wouldn’t it be cool if we had some software that could spot the issue for us? If we run that code with Flow, here’s what we get:
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ flow-example.js:8:13 Cannot call getFullName with object literal bound to user because property name is missing in object literal [1]. 5│ return [first, middle, last].filter(Boolean).join('') 6│ } 7│ [1] 8│ getFullName({first: 'Joe', middle: 'Bud', last: 'Matthews'}) 9│ 10│
So without changing our code at all, we get notified something’s wrong. Nice! Now, what if we add type annotations?
// @flow type User = { name: { first: string, middle: string, last: string, }, } function getFullName(user: User): string { const {name: {first, middle, last}} = user return [first, middle, last].filter(Boolean).join('') } getFullName({first: 'Joe', middle: 'Bud', last: 'Matthews'})
Now if we run Flow on this, the error is even more helpful:
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ flow-example.js:15:13 Cannot call getFullName with object literal bound to user because property name is missing in object literal [1] but exists in User [2]. [2] 10│ function getFullName(user: User): string { 11│ const {name: {first, middle, last}} = user 12│ return [first, middle, last].filter(Boolean).join('') 13│ } 14│ [1] 15│ getFullName({first: 'Joe', middle: 'Bud', last: 'Matthews'}) 16│ 17|
I like to consider type definitions with Flow or TypeScript to be a form of inline automated tests. I strongly recommend you give it a shot if you haven’t yet. Incremental adoption is possible with these tools (especially if you’re already using babel, you can just start using babel-preset-{flow,typescript}
). Try it out on your next feature and see what you think.
Conclusion
Static code analysis is a great way to get a significant boost of confidence—fast, easily, and with less effort than writing unit tests for the entire codebase. That’s why it forms the base of the Testing Trophy 🏆. If you’re not using these tools already, start now.
Oh, and that big thing I’m working on that I’ve been teasing you about? I’ve got a bunch of stuff in there showing how to set up these tools. Look forward to it 😉
Looking for a job? Looking for a developer? Check out my job board: kcd.im/jobs
Things to not miss:
- React… Suspense… (@ SLC frontend meetup) - Livestream of my talk at https://www.meetup.com/SLC-FE-DEV/eve…. In this talk I build my own simple-cache-provider to teach you how React Suspense works with the cache and resources (promise throwers).
- Last call for Create React App v2 + Using and writing custom babel macros with create-react-app v2 (which is a DevTipsWithKent livestream)
- Validation with HTMLInputElements - A DevTipsWithKent livestream where I show you a sweet validation feature that’s built-into browsers since IE10!
Some tweets from this last week:
> So this app just changed my life: (link: https://getpixelsnap.com/) getpixelsnap.com > > PixelSnap: “The fastest way to measure everything on screen.” – Sep 27, 2018 (has a video demo)
> If you haven’t seen your Coverage report in > @ChromeDevTools > yet, pull it up now. You’ll probably be very surprised how much unused code your users are loading, parsing, and evaluating. What a waste! > > developers.google.com/web/updates/20… > > #CodeSplitting – Sep 24, 2018
> I would much rather have 30 tests break all at once due to one bug because they’re integration tests than have no tests break because I mostly unit tested and didn’t consider testing a specific integration point. > > kcd.im/write-tests – Sep 26, 2018
> Hey friends!!!! > > I’m just reviewing some videos that I’m working on for that HUGE course thing I’ve been teasing you about… > > This is going to be awesome. You’re going to love it. I can’t wait!!! > > 🔜 – Sep 26, 2018
This week’s blog post is “React/JSX as a server-side templating language”. It’s the published version of my newsletter from 2 weeks ago. If you thought it was good, go ahead and give it some claps (👏x50) and a retweet:
P.S. If you like this, make sure to subscribe, follow me on twitter, buy me lunch, support me on patreon, and share this with your friends 😀
👋 Hi! I’m Kent C. Dodds. I work at PayPal as a full stack JavaScript engineer. I represent PayPal on the TC39. I’m actively involved in the open source community. I’m an instructor on egghead.io, Frontend Masters, and Workshop.me. I’m also a Google Developer Expert. I’m happily married and the father of four kids. I like my family, code, JavaScript, and React.