Blog
Posts on software development, careers, and craft.
In the age of AI, code reviews are more important than ever
In the age of AI, code reviews are more important than ever. The developer may not have read the code.
New React framework: One Strongly typed file-based routes (like Tanstack...
New React framework: One Strongly typed file-based routes (like Tanstack router) Loaders (like Remix/React Router) SPA, RSC, SSG support, with per...
Problem: SQL is an old, leaky abstraction
Problem: SQL is an old, leaky abstraction. It doesn’t play nice with typed languages. Just learned about an alternative called Convex. Idea: Strong...
Perhaps the most common mistake I see in TypeScript code reviews: Needless...
Perhaps the most common mistake I see in TypeScript code reviews: Needless optional properties. People seem to think "I'll make this optional just...
Just saw this performance mistake in a React code review
Just saw this performance mistake in a React code review. Problem: If you invoke a function in useState's default, it's called on every render. (No...
9 ways I’ve made money as a software dev, sorted from most enjoyable to least: 1
9 ways I’ve made money as a software dev, sorted from most enjoyable to least: 1. Independent consultant and developer 2. Teaching workshops at com...
Problem: The backend returns a needlessly wide type
Problem: The backend returns a needlessly wide type. Example: The backend returns null, undefined, or an array. Solutions: (ranked by preferability...
Somehow I overlooked this new React 19 feature until now: Problem: I want to...
Somehow I overlooked this new React 19 feature until now: Problem: I want to run some code when *any* caught or uncaught error occurs in my React a...
These days, many old JavaScript projects have converted to TypeScript
These days, many old JavaScript projects have converted to TypeScript. If you haven’t yet, here’s a compelling stat: A survey of six months worth o...
Every developer has to balance two concerns: 1
Every developer has to balance two concerns: 1. Be tactical - Get it done as soon as possible. Cut corners if necessary. Favor delivery over qualit...
React mistake: State too high
React mistake: State too high. If state is merely passed down to one child, it’s too high. It should be moved down to the child. Benefits: - Elimin...
Situation: A web app has no end-to-end (E2E) tests
Situation: A web app has no end-to-end (E2E) tests. Solution: Consider writing E2E tests in phases. Phase 1: Smoke test - Write E2E tests that mere...
I occasionally see people using HTML entities like ' or "
I occasionally see people using HTML entities like ' or ". Now that UTF-8 is ubiquitous, there's typically no need to do so anymo...
I’ve been happily using Vitest for quite awhile, but I just tried using Jest...
I’ve been happily using Vitest for quite awhile, but I just tried using Jest again. Ouch. I remember when Jest was easy to use, but I hit a number...
7 things I search for when I audit a TypeScript codebase: any - Use a...
7 things I search for when I audit a TypeScript codebase: any - Use a narrower type. ?. - Avoid by narrowing type. ?: - Optional properties are oft...
“I’ll add tests in an upcoming PR.” When I hear this, I push back
“I’ll add tests in an upcoming PR.” When I hear this, I push back. Here's why. - Tests make the PR easier to review to understand. Tests are docume...
Great advice from “A Philosophy of Software Design”
Great advice from “A Philosophy of Software Design”. Prefer deep modules. (Yes, I’m enjoying this read on the beach! 🏖️)
I had a wonderful job, but I always dreamed of being independent
I had a wonderful job, but I always dreamed of being independent. I knew it might require grinding for years to get there. So, I spent countless ni...
React performance mistake: Calling a function multiple times with the same args
React performance mistake: Calling a function multiple times with the same args. Solution: Call the function once above the JSX.
TypeScript problem: A subset of fields are optional, but should all be...
TypeScript problem: A subset of fields are optional, but should all be populated if one is populated. Solution: 1. Put related properties under an...
Problem: I want strongly typed React search params
Problem: I want strongly typed React search params. Solutions: Using React Router or Remix? Wrap useSearchParams in a custom hook and parse the par...
I'm ready for AI that's pushy, like a smarter linter
I'm ready for AI that's pushy, like a smarter linter. I want an AI that says "This variable name is misleading. Click here to rename to x." Same fo...
Problem I just saw in a code review: Using useEffect to copy URL search...
Problem I just saw in a code review: Using useEffect to copy URL search params to state. Solution: Use the URL as the single source of truth. Example:
Just used Cursor to eliminate a needless useEffect in a big React component
Just used Cursor to eliminate a needless useEffect in a big React component. I simply asked "Can you eliminate this useEffect?" The explanation was...
I love being a software developer
I love being a software developer. But, I have concerns about the future of software development as a career. Four reasons: 1. AI is radically incr...
React is typically fast enough
React is typically fast enough. But here's a simple way to optimize performance: Decompose components so state changes impact a small amount of JSX...
I care about code quality
I care about code quality. But, I also recognize it’s a tradeoff. My old boss didn’t believe in automated testing. He thought worrying about “code...
I'm tired of bad test names
I'm tired of bad test names. Examples: 🚩Renders 🚩Form validation 🚩Submit button Good test names describe two things: 1. The scenario under test...
Problem: I want to require a specific format for a TypeScript string
Problem: I want to require a specific format for a TypeScript string. Solution: Template literal type. Example: In react-switchboard, each state ke...
I’m looking forward to useActionState in React 19
I’m looking forward to useActionState in React 19. Here are six useActionState benefits: 1. No event.preventDefault needed. 2. Can read the form’s...