Slopapalooza

What it is

The 9,000-Line Component is a component that accumulates unrelated responsibilities as AI adds one requested feature after another. Data fetching, rendering, business rules, and side effects become tangled in one place. Colocating a screen’s fetching and rendering can be a sensible design. The problem starts when changes to one concern require understanding or modifying several others that should be independent.

How it happens

Each individual change makes sense in isolation. “Add a tooltip here.” “Handle the loading state.” “Add the empty case.” Each prompt is small, each diff looks reasonable, and the AI extends the file you point it at. Nobody zooms out.

In an illustrative checkout, the discount calculation reads values directly from component state populated by a shipping request. Testing a change to coupon rounding means mounting the screen and arranging a shipping response before the calculation can run. That network setup has nothing to do with the rounding rule. Moving the last 500 lines into CheckoutHelpers leaves the dependency intact if the helpers still reach back into the same state.

Warning signs

  • A display change forces the reviewer to understand payment or pricing rules.
  • Several handlers mutate the same state, and nobody can say which one owns it.
  • Tests for a simple calculation need to mount the whole screen and arrange network responses.
  • Reviewers trust each small diff because the component as a whole is too much to follow.
  • Changes here take longer than comparable changes elsewhere, and people quietly route around it.

Why it’s dangerous

A local edit can change behavior far from the line being edited. When pricing and request state are intertwined, a harmless-looking loading-state fix deserves a much wider review. The next AI session sees the existing arrangement and can extend it again. The file becomes a black hole that bends every nearby change toward itself.

Line count alone cannot tell you whether a component is poorly designed. Some responsibilities belong together. Extracting each handler into its own hook can replace one readable flow with a tour of six files. AI can help trace which state and rules change together; use that evidence to choose a split, rather than treating a folder full of small files as proof of good design.

How to prevent it

Choose a split by naming the dependency it removes. In the checkout, let the price calculation accept items, coupon rules, and a shipping rate as values. The checkout still obtains those values and sequences requests, but the calculation no longer requires a screen or network connection. Keep the extraction separate from changing the pricing rules.

For UI code, React’s component design guide demonstrates splitting by responsibility and choosing where shared state belongs.

The serious team fix

  1. Trace one difficult change. Ask AI to show which state, handlers, and callers participate in it. Check that map against the code before choosing an extraction. “This file is long” gives you less to work with than “testing rounding needs a shipping-service response.”
  2. Give the result one owner. Have the checkout use the extracted calculation for both the displayed total and order submission. Copying its result into several independently updated state variables would recreate the synchronization problem in smaller files. This keeps the UI consistent; the server must still validate pricing when accepting the order.
  3. Check the behavior across the new boundary. For the checkout example, test the rounding rule independently, then check the wiring: after a coupon changes, does the submitted order use the newly calculated total?

The next pricing change should require less context to make correctly. That is a useful result to look for after the split. A lower line count is just an easy one to put in the PR description.

Related anti-patterns

Back to all anti-patterns