This week, weâve got a new way to feel something test your code, some bundler fan fiction, and the hardest diss of the 18th Century.
Welcome to #102.
My first (and last) testing conference
Fact checking your terrible tests
Version 3.0.0 of fast-check
, a âproperty-based testingâ library for JavaScript, came out last week. If youâre not familiar, be thankful youâre hearing about it from us and not the obnoxious guy (yes guy) on your team who spends more time arguing about functional programming than getting work done.
Whatâs Property-Based Testing? Most developers write tests like they do estimates: give the best case scenario and hope it all works out. These lies hardcoded inputs (đĽ¸) are called âexample based testsâ.
With property-based tests, your test is run hundreds of times with different autogenerated inputs. Itâs kind of like having an automated QA person that fact checks your code. fast-check
is the most popular library for doing this with JavaScript (and TypeScript).
How does it work? fast-check
provides a bunch of utilities for defining the âpropertiesâ of your code (things you assume will always be true). It uses them to generate random inputs to test against your code. When a test fails, fast-check
helps narrow down the (đŠ ton of) failed cases to a single reproducible case that you can âreplayâ to verify the fix.
Ngl, itâs a lot to take in but they provide a handy set of tips and interactive examples to help you get get familiar.
Property based testing might be for you if you:
- Need help detecting race conditions
- Need to find edge cases when you canât conceivably know all the possibilities
- Want less tests but with better coverage
Bottom Line: If you want to stop wasting your time with terrible tests, you can A) delete them all (galaxy brain) or B) go all in and use property based testing. Weâre big fans of A), but if math is your kink, fast-check
might be worth your time.
Don't be like Elmo. [sponsored]
Sleuth.io can actually make your team more efficient
Tracking âdeveloper productivityâ is stupid.
Two reasons:
- Developers hate it (spying on me to see if Iâm a âproductive developer,â actually makes me a way less productive developer)
- It doesnât work (âwhoever writes the most lines of code/closes the most tickets is the best developerâ is⌠really dumb?)
Thatâs why Sleuth is the best. It doesnât track developer productivity â it only measures team output. And it actually works.
Thatâs because it captures your teamâs DORA metrics â which multiple studies have shown are the only stats that actually matter. No worthless vanity metrics and no individual stats.
Sleuth automatically collects all that data for you (including deploys), unlike most other services that only collect git or issue tracker data. So you can trust that the numbers are legit.
Itâs also worth noting that Atlassian uses Sleuth. Thatâs like being Chef Gordon Ramseyâs favorite restaurant â if it works for them, itâll probably help you too.
Try it free and help your team reach its goals faster.
Y'all still looking for a bundler?
Letâs get ready to bundle
Back in 2018, Airbnb did what lots of us have done when thinking about upgrading to a new version of Webpack â give up.
Unfortunately for them, this was before The Great Build Tool Renaissanceâ˘ď¸ of the last couple years â esbuild and Rollup werenât around yet, Parcel wasnât as robust as it is today, and Rome was still just a European city with lots of roads.
So they turned to Metro, Facebookâs open-source JavaScript bundler for React Native.
This was a surprising choice for Airbnbâs web app, and it required them to work directly with the Metro team to create their own custom flavor of Metro (yum) that could handle bundling all of Airbnbâs web properties. The 4-year odyssey finally ended last week with an interesting retro outlining the entire process.
So letâs dive a little deeper into what makes Metro unique, why Airbnb decided to use it, and how it stacks up to some of the newer bundlers we have today.
There are two defining Metro features:
-
On-demand bundle processing in development â Metro only compiles JS bundles on the pages requested, as opposed to pre-compiling the entire project from the start (like Webpack).
-
Multi-layered cache â You can set up multiple caches to be used by Metro, and you get the flexibility to define the cache implementation you want.
For most projects, implementing these optimizations would probably feel like extreme hair-splitting (my favorite Winter X-Games event). But for a huge app like Airbnb with 49k+ JS modules, it produced great results, including 80% faster TTI (Time to Interactive) and 55% faster compiling of the slowest prod build. đ
Should you try this at home? Probably not, tbh. In The Year of Our Build 2022, we have better options for powerful, flexible bundlers that donât require years of customization (esbuild is probably the gold standard for most projects).
But you could always just wait around for a couple years until we inevitably get something even faster.
Jobs
Flightcontrol recently completed YCombinator and raised $3.3m. Theyâre a fully remote team thatâs focused on solving the huge gap between Heroku and AWS, and theyâre led by Brandon Bayer, the creator of Blitz.js.
Close.com is looking for 3 experienced individuals that have a solid understanding of React and want to help design, implement and launch major user-facing features. Close is a 100% globally distributed team of ~55 high-performing, happy people that are dedicated to building a product our customers love.
Yeti Labs is a human-centered frontend studio designing and building web apps for DeFi protocols. We love UI animations, innovative UXs, best practices, reusing our code, improving our workflow and learning new things. Come join our crew as we solve interesting challenges while having fun.
đŹ Spot the Bug â Sponsored by CarbonQA
CarbonQA provides QA services geared for dev teams. Let us lift your dev teamâs morale by breaking their code. We work in your tools, talk with your team in Slack, and let devs be devs. Leave the testing to us.
import db from "./db";
import admin from "firebase-admin";
import { getUserClaimsFromCookie } from "./claims";
const { arrayUnion, arrayRemove } = admin.firestore.FieldValue
export default async function updateLessonComplete(req, res) {
try {
const { lessonId, completed } = req.body
if (!lessonId) {
throw new Error("lessonId is a required parameter");
}
if (!completed) {
throw new Error("completed is a required parameter");
}
const claims = await getUserClaimsFromCookie(req, res);
if (!claims) {
throw new Error('user must be logged in')
}
await db.collection('lessons').doc(lessonId)
.update({
completed: completed === true
? arrayUnion(claims.uid)
: arrayRemove(claims.uid)
})
res.send({ status: "success" });
} catch (e) {
res.status(400);
res.send({ error: { message: e.message } });
}
}
Cool Bits
-
Curious about whatâs happening in Java-land? New Relicâs got you covered with their 2022 State of the Java Ecosystem Report. [sponsored]
-
The new React docs got some performance upgrades after Evan You and Dan Abramov went head to head in a battle of the subtweets. Iâm sad that neither of them found a way to use the hardest diss of the 18th Century, but thereâs always next time.
-
Speaking of Twitter beefs between framework authors, Next.js just shared their new Layouts RFC â which is basically just Remix (Taylorâs Guillermoâs Version). Hereâs a quick TLDR we made to catch you up to speed.
-
Austin Gil wrote an in-depth article about Why Edge Compute is kind of like knitting dog hats. Personally, I think itâs a lot more like crocheting, but thatâs just one personâs opinion.
-
Tailwind 1.6 was just released with a new Tailwind language mode for VS Code and some other cool features to help you feel good at design.
-
Danny Hermes wrote a great article about What npm Can Learn from Go and that has us thinking, why is âCanâ capitalized but not âFromâ?
-
Digital Ocean just announced DO Functions and officially entered the serverless computing battle royale.
-
Ken Kantzer wrote up his learnings from 5 years of doing tech startup code audits. Specializing in âcode audits for startupsâ sounds about as much fun as specializing in âbehavior management for middle schoolersâ, but Iâm glad there are good people out there doing both.
đŹ Spot the Bug Solution â Sponsored by CarbonQA
import db from "./db";
import admin from "firebase-admin";
import { getUserClaimsFromCookie } from "./claims";
const { arrayUnion, arrayRemove } = admin.firestore.FieldValue
export default async function updateLessonComplete(req, res) {
try {
const { lessonId, completed } = req.body
if (!lessonId) {
throw new Error("lessonId is a required parameter");
}
if (!completed) {
throw new Error("completed is a required parameter");
}
const claims = await getUserClaimsFromCookie(req, res);
if (!claims) {
throw new Error('user must be logged in')
}
await db.collection('lessons').doc(lessonId)
.update({
completed: completed === true
? arrayUnion(claims.uid)
: arrayRemove(claims.uid)
})
res.send({ status: "success" });
} catch (e) {
res.status(400);
res.send({ error: { message: e.message } });
}
}
Thereâs a lot of misdirection here. The bug happens with our if (!completed)
check. completed
is a boolean, meaning when completed
is false
(making it falsy), our code will throw an error. Instead, we can check if completed
is of type boolean
, not if itâs falsy.
if (typeof completed !== 'boolean') {
throw new Error("completed is a required parameter");
}
and before you say it, yes, I know TypeScript prevents this đ.
Share Bytes
We work hard to make Bytes something you'd want to share with your
developer friends. And to make it a little easier, we'll give you free
stuff when you do.
Have a product you think our developers will love?
Advertise in Bytes
50 W Broadway Ste 333 PMB 51647 Salt Lake City, Utah 84101
Unsubscribe from Bytes