Stack Overflow report: Duplication can cost less than wrong abstraction

Merging three similar-looking user interface workflows into a single reusable component can cost more code coordination and maintenance than the duplication it removes, stackoverflow.blog reported this week.

The Hidden Coordination Costs of Abstracting Approve, Change, and Move Workflows

Every developer working in frontend engineering eventually receives the standard architectural advice: find similar screens, create an abstracted component, and delete the extra code. However, following that reflex blindly introduces severe engineering pitfalls. Consider a legacy system managing three distinct item actions: workflow approval, workflow modification, and workflow relocation. At a superficial glance, the interface requirements appeared identical. Each action featured an item list, a selection mechanism, a confirmation step, and a results toast notification. Tables, pop-ups, and UI states matched across the board.

Faced with this surface-level repetition, a developer combined all three paths into a single shared component. That single abstraction quickly unraveled. The underlying business logic diverged sharply. Workflow approval represented an assertion about the future, whereas modification occurred instantly. Relocation required an entirely separate external system to accept the request, creating an asynchronous failure boundary where rejection was possible.

As edge cases piled up, the shared component accumulated conditional props like mode, variant, showDetails, requireReason, and onSpecialCase. Any future alteration to the confirmation procedure required agreement from all three workflow owners. A modification in one feature area triggered arguments and regression risks across the others. The wrong abstraction proved significantly more expensive to unwind than simple duplication.

Don’t Build the Reusable Component Yet
Photo: daily.dev

Applying the Rule of Three Before Writing Shared Components

Duplication is frequently cheaper than the wrong abstraction. To avoid premature componentization, engineers should apply the “Rule of three”—a principle attributed to Don Roberts in Martin Fowler’s seminal book Refactoring. As daily.dev noted in its coverage of architectural trade-offs, code should remain duplicated until the exact same pattern repeats three times for the exact same underlying reason for change. Sandi Metz explored this dynamic in her essay The Wrong Abstraction, while Kent C. Dodds advocates for similar restraint through AHA (Avoid Hasty Abstractions) programming.

To determine whether identical-looking code represents true duplication or mere coincidence, engineers can apply a straightforward diagnostic question. If a requirement changes, who would need to be consulted, and would all copies change simultaneously? If the answers vary across the implementations—such as a submit endpoint tied to an approval policy versus one governed by validation rules—the code shares only a coincidental resemblance.

By contrast, certain foundational elements remain safe to abstract from day one because their shape is stable and externally defined. These exceptions include basic primitives like buttons and text inputs, design tokens handling colors and spacing, accessibility behaviors like keyboard movement and focus trapping, and standards-driven utilities such as currency formatters and protocol clients.

Inlining Code to Restore Architectural Autonomy

When an existing abstraction proves overly coupled, the most effective remediation strategy is retrograde: inline the common module directly back into each call site. Developers can copy the module’s internal code into individual workflows and strip out the branching logic that specific workflow never executes. This restores independent ownership, allowing each screen to evolve without requiring cross-team permission.

Once individual workflows stabilize and genuine duplication emerges naturally three times for the same architectural reason, smaller pieces like shared tables or date formatters can be safely extracted. Avoiding premature abstractions protects engineering velocity, ensuring that codebases scale through modular independence rather than fragile, over-parameterized components.

Photo of author

Sophie Lin - Technology Editor

Sophie is a tech innovator and acclaimed tech writer recognized by the Online News Association. She translates the fast-paced world of technology, AI, and digital trends into compelling stories for readers of all backgrounds.

Jodie Burrage Reveals Online Abuse After Chennai Defeat

Fewer than Half of NHS Staff Received Flu Jab Last Year