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!

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.

  • 329
Loading comments...

More from Kent C. Dodds