Kent C. Dodds

Don't Solve Problems

Eliminate Them

Let's wake up

Your brian needs this 🧠

What this talk is

  • Problems, Solutions, and Trade-offs
  • Solving < Eliminating < Avoiding

Don't Solve Problems. Eliminate Them.

What this talk is not

  • Code examples
  • 100% about code
  • Domain-specific

Don't Solve Problems. Eliminate Them.

Problem Tree

Problems lead to solutions lead to problems

You are a problem solver

You are a problem seeker

Storytime

"Possibly the most common error of a smart engineer is to optimize the thing that should not exist" – Elon Musk

It's better to avoid problems than to solve them.

Avoidance Problem Tree

Unavoidable Problems

You should be a problem eliminator

Solutions hold you captive

Problems "solved"

  • Exhaust
  • Stopping
  • Car Fires
  • Sustainability

Problems Eliminated

(mostly)

  • Exhaust
  • Stopping
  • Car Fires
  • Sustainability

Elimination Problem Tree

Tesla's Giga Casting

Problem Elimination

In software

React and Code Reuse

<Chart>
    {render => props}</Chart> ?

withChart(HOC) ?

From "Thinking in React Hooks" by Amelia Wattenberge
wattenberger.com/blog/react-hooks

Functions!

What kentcdodds.com is

General stats

  • 27k lines of code
  • PM, Designer, Illustrator, UI Dev + me + some other contributors (/credits)

Nested Routing

Seamless Client/Server

Web Foundation

Simple Mutations

CSS Loading *and* Unloading

Client

Server

// look mah! No useEffect, isLoading, or isError!
export async function loader({ request }: DataFunctionArgs) {
	return json({ teamsInOrder: shuffle(teams) })
}

export default function NewAccount() {
	const data = useLoaderData<typeof loader>()

	return (
		// some UI stuff...

		<fieldset className="contents">
			<legend className="sr-only">Team</legend>
			{data.teamsInOrder.map(teamOption => (
				<TeamOption
					key={teamOption}
					team={teamOption}
					error={actionData?.errors.team}
					selected={formValues.team === teamOption}
				/>
			))}
		</fieldset>

		// more UI stuff
	)
}
// note filtering out the stuff we don't need and the declarative error handling

export async function loader({ params, request }: DataFunctionArgs) {
	// getSeasonListItems hits the simplecast API and filters out
	// all the extra stuff we don't need for this route
	const seasons = await getSeasonListItems({ request })
	const seasonNumber = Number(params.season)
	const season = seasons.find(s => s.seasonNumber === seasonNumber)
	if (!season) {
		throw new Response(`No season for ${params.season}`, { status: 404 })
	}

	return json(
		{ season },
		{
			headers: {
				'Cache-Control': 'public, max-age=600',
			},
		},
	)
}

export default function ChatsSeason() {
	const { season } = useLoaderData<typeof loader>() // <-- autocompleted
	return <stuff />
}

export function ErrorBoundary() {
	return (
		<GeneralErrorBoundary
			statusHandlers={{
				404: ({ params }) => (
					<Grid nested className="mt-3">
						<div className="col-span-full md:col-span-5">
							<H3>{`Season not found`}</H3>
							<Paragraph>{`Are you sure ${
								params.season ? `season ${params.season}` : 'this season'
							} exists?`}</Paragraph>
						</div>
						<div className="md:col-span-start-6 col-span-full md:col-span-5">
							<MissingSomething className="rounded-lg" aspectRatio="3:4" />
						</div>
					</Grid>
				),
			}}
		/>
	)
}
  • fetch Request/Response
  • <Form />
  • <link rel="modulepreload" />
  • <link rel="prefetch" as="fetch" />

Web Foundation

import type { LinksFunction } from 'remix'
import aboutStyles from '~/styles/routes/about.css'

export const links: LinksFunction = () => {
	return [{ rel: 'stylesheet', href: aboutStyles }]
}

export default function AboutScreen() {
	return <stuff />
}

CSS Loading *and* Unloading

Simple Mutations

  1. Loaders run in parallel
  2. Remix loads only what's needed
  3. Mutations trigger invalidation of all loaders
  4. Context for shared UI state & Remix for shared server state
  5. No <Layout /> component

/

:userId

users/

Nested Routing

&

Trade-offs

Eliminate big problems in exchange for smaller problems.

Conclusion

Solving

< Eliminating

< Avoiding

If you can't avoid the problem, try to eliminate it by changing your approach.

And only if that fails, solve the problem.

Let's make the world better

Thank you!