When the same logic appears in three or more places, extract it into a shared function, hook, or module. Duplicated code means that when you fix a bug or change behavior in one copy, the other copies silently remain broken — leading to inconsistent behavior, hard-to-trace bugs, and wasted time tracking down "why does it work here but not there."
Duplicated logic creates consistency bugs — when you fix a bug or change behavior in one copy, the other copies remain broken. With 3+ copies, the probability of missing one during a change approaches certainty. Extraction at the right time reduces maintenance burden without premature abstraction.
BeforeMerge scans your pull requests against this rule and 3+ others. Get actionable feedback before code ships.
The "Rule of Three" is a pragmatic guideline: tolerate duplication twice, extract on the third occurrence. This balances two competing risks:
When the same logic appears in 3 or more places, extract it to the appropriate layer:
// In user-profile.tsx
function formatUserName(user: User) {
return user.name
? `${user.name} (@${user.username})`
: `@${user.username}`;
}
// In comment-card.tsx — same logic, copy #2
function formatAuthor(author: User) {
return author.name
? `${author.name} (@${author.username})`
: `@${author.username}`;
}
// In team-member-list.tsx — same logic, copy #3
function getMemberDisplay(member: User) {
return member.name
? `${member.name} (@${member.username})`
: `@${member.username}`;
}Three copies with different function names but identical logic. When the format needs to change (e.g., adding verified badges), you must find and update all three.
// lib/utils/format-user.ts — single source of truth
export function formatUserDisplayName(user: { name?: string; username: string }) {
return user.name
? `${user.name} (@${user.username})`
: `@${user.username}`;
}// All three components import the shared function
import { formatUserDisplayName } from "@/lib/utils/format-user";
// user-profile.tsx
<span>{formatUserDisplayName(user)}</span>
// comment-card.tsx
<span>{formatUserDisplayName(comment.author)}</span>
// team-member-list.tsx
<span>{formatUserDisplayName(member)}</span>The extraction target depends on what the duplicated code does:
| Duplicated code | Extract to |
|---|---|
| UI rendering pattern | Shared component |
| State + effect logic | Custom React hook |
| Data transformation | lib/utils/ function |
| API call pattern | lib/services/ function |
| Validation logic | Shared Zod/Yup schema |
| Database query | lib/repositories/ function |
Duplication detection is best done during code review. Look for:
try/catch patterns across multiple filesAutomated tools like jscpd can detect copy-paste patterns:
npx jscpd --min-lines 5 --min-tokens 50 src/