Don't Solve Problems

Eliminate Them

Kent C. Dodds

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.

Let's
Get
STARTED!

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 const loader: LoaderFunction = async ({request}) => {
  const values: LoaderData = {
    teamsInOrder: shuffle(teams),
  }
  return json(values)
}


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

  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

type LoaderData = {
  season: CWKSeason
}

export const loader: LoaderFunction = async ({
  params,
  request,
}) => {
  // 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})
  }

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

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

// handles unexpected errors
export function ErrorBoundary({error}: {error: Error}) {
  console.error(error)
  return <ServerError />
}

// handles our thrown 404 response
export function CatchBoundary() {
  const caught = useCatch()
  const params = useParams()
  console.error('CatchBoundary', caught)
  if (caught.status === 404) {
    return (
      <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>
    )
  }
  throw new Error(`Unhandled error: ${caught.status}`)
}
  • fetch Request/Response
  • <Form />
  • <link rel="modulepreload" />
  • <link rel="prefetch" as="fetch" />

CSS

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 />
}

Client-side server state cache management & Nested Routing

  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/

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!