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!

Don't Solve Problems, Eliminate Them.

By Kent C. Dodds

Don't Solve Problems, Eliminate Them.

Humans are natural problem solvers and we're good enough at it that we've survived over the centuries and become the dominant species of the planet. Because we're so good at it, we sometimes become problem seekers too–looking for problems we can solve. Those who most successfully accomplish their goals are the problem eliminators. Let's talk about the distinction between solving and eliminating problems with examples from inside and outside the coding world.

  • 2,726