I stopped rewriting junior devs’ code. I refactor it with them instead. Last week, a dev on my team built a settings form. It worked. Every feature was there. But the component was **380 lines**. Here’s what we changed together and why. The original had: 8 useState calls in one component. 40 lines of if/else for validation. fetch() inside an onClick handler. window.alert() for errors. No separation. No reusability. No tests. After refactoring: const schema = z.object({ name: z.string().min(1), email: z.string().email(), }); 8 lines replaced 40 lines of if/else. Type-safe. Reusable across every form. const { mutate, isPending } = useMutation({ mutationFn: updateSettings, }); Retry, caching, error handling — all built in. No manual try/catch. No setLoading. We extracted everything into: useSettingsForm.ts — state + logic settingsSchema.ts — validation SettingsForm.tsx — 64 lines, UI only 380 lines became 64. 8 useState calls became 0. 1 untestable file became 4 testable ones. But the biggest lesson wasn’t the code. Junior thinks: “How do I make this work?” Senior thinks: “How will someone else change this?” That’s the entire gap. Not talent. Not years of experience. Just exposure to codebases where things break and 3 people need to touch your code. The best way to level up: Don’t just read senior code. Refactor yours with them. Every PR review is a free mentoring session. What’s the biggest refactoring lesson you’ve learned from a code review? #React #TypeScript #WebDevelopment
The Zod part surprised the junior dev the most. They were writing 40 lines of manual validation. I showed them 8 lines of Zod schema that: → Validates on client AND server → Generates TypeScript types automatically → Gives user-friendly error messages → Is reusable across every form in the app They said: “Why didn’t anyone teach me this?” That’s the real problem. We don’t teach patterns.
The refactored file structure: useSettingsForm.ts — custom hook (state + submit) settingsSchema.ts — Zod validation (8 lines) SettingsForm.tsx — 64 lines, pure UI ErrorBoundary.tsx — reusable error wrapper 4 files. Each under 80 lines. Each independently testable. The junior version was 1 file, 380 lines, and you couldn’t test any part without rendering the whole thing. Separation of concerns isn’t about more files. It’s about code that doesn’t break when requirements change.
Absolutely wrong!!! Using libraries isn't what distinguishes between junior and senior! A junior can copy-paste zod and react-query too — that doesn't make them senior. What actually separates them is problem solving ability, knowing when not to use a library, understanding trade-offs, handling edge cases, debugging under pressure, and writing code that a team can maintain 6 months later. Measuring seniority in "lines reduced" is the most junior take of all.
Is senior by number of lines and validation packages?
Very informative
Huseyin Kaplan We also aren't taught all the best libraries. I didn't know about Zod or react-hook-form until I randomly stumbled upon it in someone else's YouTube video. Now it's second nature for me, but we can't expect juniors to know what they don't know.
bundle size: 174kB -> 5MB
Interesting comparison, though in large production systems simplicity and readability often matter more than reducing line count.
One more thing, the junior dev asked: “Should I always use React Query for API calls?” My answer: depends on what you’re building. Server Components (Next.js App Router)? → Fetch directly. No client-side library needed. Client-side interactive data (dashboards, real-time)? → React Query or SWR. One-off script or prototype? → useEffect + fetch is fine. The senior skill isn’t knowing the tool. It’s knowing WHEN to use which tool.