{"id":29079442,"url":"https://github.com/nyaomaru/technical-debt-sample","last_synced_at":"2026-04-12T17:32:55.556Z","repository":{"id":298298182,"uuid":"994173117","full_name":"nyaomaru/technical-debt-sample","owner":"nyaomaru","description":"Technical debt sample for order form","archived":false,"fork":false,"pushed_at":"2025-06-10T10:57:38.000Z","size":317,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-06-10T11:41:33.635Z","etag":null,"topics":["nextjs","react","react-hook-form","refactoring","sample-project","shadcn-ui","tailwindcss","technical-debt","typescript","zod"],"latest_commit_sha":null,"homepage":"https://technical-debt-sample.vercel.app","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nyaomaru.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-06-01T11:28:35.000Z","updated_at":"2025-06-10T10:57:10.000Z","dependencies_parsed_at":"2025-06-10T11:41:35.730Z","dependency_job_id":"3ef5223d-b25e-44bb-a318-f507790bcfd7","html_url":"https://github.com/nyaomaru/technical-debt-sample","commit_stats":null,"previous_names":["nyaomaru/technical-debt-sample"],"tags_count":0,"template":true,"template_full_name":null,"purl":"pkg:github/nyaomaru/technical-debt-sample","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nyaomaru%2Ftechnical-debt-sample","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nyaomaru%2Ftechnical-debt-sample/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nyaomaru%2Ftechnical-debt-sample/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nyaomaru%2Ftechnical-debt-sample/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nyaomaru","download_url":"https://codeload.github.com/nyaomaru/technical-debt-sample/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nyaomaru%2Ftechnical-debt-sample/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262298688,"owners_count":23289601,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["nextjs","react","react-hook-form","refactoring","sample-project","shadcn-ui","tailwindcss","technical-debt","typescript","zod"],"created_at":"2025-06-27T17:02:52.379Z","updated_at":"2025-10-27T00:37:11.715Z","avatar_url":"https://github.com/nyaomaru.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Technical Debt Sample\n\nThis repository demonstrates how to refactor a form component suffering from technical debt.\n\nIt is built with `Next.js` (App Router), `zod`, `React Hook Form (RHF)`, and `shadcn/ui`.\n\n---\n\n## Philosophy\n\n- Feature-based architecture with App Router\n- Form validation using `zod`\n- Form logic implemented using `react-hook-form`\n- UI styled with `tailwindcss` and `shadcn/ui` components\n\n---\n\n## Problem\n\nImagine you created a bloated `OrderForm` component like this:\n\n\u003cdetails\u003e\n\u003csummary\u003eClick to expand code sample\u003c/summary\u003e\n\n```tsx\nimport { useState, useEffect } from 'react';\nimport {\n  stepOneSchema,\n  stepTwoSchema,\n  stepThreeSchema,\n  stepFourSchema,\n} from './formSchema';\n\ntype Form = {\n  customerName: string; // Step1\n  email: string; // Step1\n  phone: string; // Step2\n  orderId: number; // Step3\n  discountCode?: number; // Step3 (only special)\n  remarks?: string; // Step4 (only admin)\n};\n\nexport function OrderForm({\n  isSpecial,\n  isAdmin,\n}: {\n  isSpecial: boolean;\n  isAdmin: boolean;\n}) {\n  const [step, setStep] = useState(1);\n  const [formData, setFormData] = useState\u003cForm\u003e({\n    customerName: '',\n    email: '',\n    phone: '',\n    orderId: 0,\n    discountCode: undefined,\n    remarks: undefined,\n  });\n\n  useEffect(() =\u003e {\n    if (isSpecial) {\n      // If it is special order, init to discountCode\n      setFormData((prev) =\u003e ({\n        ...prev,\n        discountCode: 666,\n      }));\n    }\n  }, [isSpecial]);\n\n  const handleNextStep = async () =\u003e {\n    try {\n      if (step === 1) {\n        stepOneSchema.parse(formData);\n        setStep(2);\n      } else if (step === 2) {\n        stepTwoSchema.parse(formData);\n        setStep(3);\n      } else if (step === 3) {\n        stepThreeSchema(isSpecial).parse(formData);\n        // If admin user, go to step 4. Otherwise to submit.\n        if (isAdmin) {\n          setStep(4);\n        } else {\n          await handleSubmit();\n        }\n      }\n    } catch (e) {\n      console.error(e);\n    }\n  };\n\n  const handleSubmit = async () =\u003e {\n    try {\n      // Only Step4, validate stepFourSchema\n      if (isAdmin \u0026\u0026 step === 4) {\n        stepFourSchema.parse(formData);\n      }\n      await api.post('/orders', formData);\n      alert('Succeeded order！');\n    } catch (e) {\n      console.error(e);\n      alert('Denied order...');\n    }\n  };\n\n  return (\n    \u003cdiv\u003e\n      {step === 1 \u0026\u0026 (\n        \u003cStepOne\n          data={formData}\n          setFormData={setFormData}\n          onNext={handleNextStep}\n        /\u003e\n      )}\n      {step === 2 \u0026\u0026 (\n        \u003cStepTwo\n          data={formData}\n          setFormData={setFormData}\n          onBack={() =\u003e setStep(1)}\n          onNext={handleNextStep}\n        /\u003e\n      )}\n      {step === 3 \u0026\u0026 (\n        \u003cStepThree\n          data={formData}\n          setFormData={setFormData}\n          onBack={() =\u003e setStep(2)}\n          onNext={handleNextStep}\n          showDiscountField={isSpecial}\n        /\u003e\n      )}\n      {step === 4 \u0026\u0026 (\n        \u003cStepFour\n          data={formData}\n          setFormData={setFormData}\n          onBack={() =\u003e setStep(3)}\n          onSubmit={handleSubmit}\n        /\u003e\n      )}\n      {isSpecial \u0026\u0026 \u003cNoteForSpecialOrder /\u003e}\n      {isAdmin \u0026\u0026 \u003cNoteForSpecialOrder /\u003e}\n    \u003c/div\u003e\n  );\n}\n```\n\n\u003c/details\u003e\n\nThis is a typical case of technical debt — too much logic crammed into a single component, making it hard to maintain, test, or extend.\n\n## Develop\n\n### Run dev server\n\n```sh\npnpm dev\n```\n\n### Run tests\n\n```sh\npnpm test\n```\n\n### Add UI components (via `shadcn`)\n\n```sh\npnpm dlx shadcn@latest add {componentName}\n```\n\n## Related Article\n\n- [Zenn: Refactor technical debt in forms](https://zenn.dev/nyaomaru/articles/technical-debt-code)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnyaomaru%2Ftechnical-debt-sample","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnyaomaru%2Ftechnical-debt-sample","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnyaomaru%2Ftechnical-debt-sample/lists"}