๋ณ๊ฒฝ๋ ๋ผ์ฐํธ/ํ์ด์ง์ axeยทpa11yยทeslint-plugin-jsx-a11y ๊ฐ์ ์ ๊ทผ์ฑ(a11y) ์๋ ๊ฒ์ฌ๋ฅผ ๋๋ ค์ ๋ผ๋ฒจยท์ ๋๋นยทํฌ์ปค์ค ์์ยทARIA ์ญํ ๊ฐ์ ์๋ฐ์ ๊ณ ์น๊ณ , ๊ฐ์ฌ๊ฐ ๊นจ๋ํด์ง ๋(์๋ฐ 0, ์ข ๋ฃ ์ฝ๋ 0)๊น์ง ์๋์ผ๋ก ๋ฐ๋ณตํ๋ ๋ซํ ๋ฃจํ์ ๋๋ค. ์ฌ์ฉ์๊ฐ "์ ๊ทผ์ฑ ๊ฒ์ฌ ํต๊ณผํ ๋๊น์ง ๋๋ ค์ค", "a11y ์๋ฐ ๋ค ๊ณ ์ณ์ค", "์ ๊ทผ์ฑ ๊ฐ์ฌ ๊นจ๋ํด์ง ๋๊น์ง", "axe/pa11y ์๋ฐ ์ก์์ค", "์คํฌ๋ฆฐ๋ฆฌ๋ยทํค๋ณด๋ ์ ๊ทผ์ฑ ๊ณ ์ณ์ค", "run a11y audit until clean", "fix accessibility violations", "A11y Audit Until Clean"์ฒ๋ผ ์์ฒญํ๊ฑฐ๋, ๋ณ๊ฒฝํ UI์ ์ ๊ทผ์ฑ ์๋ฐ์ ๋ฐ๋ณต์ ์ผ๋ก ์ก์ ์์ ๊ณ ์ถ์ ๋ ์ฌ์ฉํ์ธ์. (๊ตฌ๋ถ: ์๊ฐ์ ํฝ์ ํ๊ท๋ looping:visual-regression-until-match, lintยทํ์ ์๋ฌ ์ ๋ฆฌ๋ looping:lint-typecheck-fix, E2E UI ํตํฉ ํ ์คํธ๋ looping:e2e-until-green)
OpenAPI๋ JSON Schema ๊ฐ์ API ๊ณ์ฝ(contract)์ ๋ง์ถฐ ๊ณ์ฝ ํ ์คํธ๋ฅผ ๋๋ฆฌ๊ณ , ์๋ต์ด ์คํ๊ณผ ์ด๊ธ๋๋ฉด(๋๋ฆฌํํธ) ํธ๋ค๋ฌ ๊ตฌํ์ด๋ ์คํ์ ๊ฐ์ฅ ์์ ๋จ์๋ก ๊ณ ์ณ์ ๊ณ์ฝ ํ ์คํธ๊ฐ ์ ๋ถ ํต๊ณผ(์ข ๋ฃ ์ฝ๋ 0)ํ ๋๊น์ง ์๋์ผ๋ก ๋ฐ๋ณตํ๋ ๋ซํ ๋ฃจํ์ ๋๋ค. ์ฌ์ฉ์๊ฐ "API๊ฐ ์คํ๋๋ก ์๋ตํ๋์ง ๊ณ์ฝ ํ ์คํธ ๋๋ ค์ค", "OpenAPI ๊ณ์ฝ์ด๋ ๊ตฌํ ์ ๋ง๋ ๊ฑฐ ๋ง์ถฐ์ค", "API ์๋ต์ด ์คํค๋ง๋ ์ผ์นํ ๋๊น์ง ๊ณ ์ณ์ค", "๋ฌธ์๋ ๊ตฌํ ๋๋ฆฌํํธ ์ก์์ค", "contract test until match", "make the API match the OpenAPI/JSON Schema contract", "API Contract Until Match"์ฒ๋ผ ์์ฒญํ๊ฑฐ๋, ๋ฌธ์์ ์ค์ ๊ตฌํ ์ฌ์ด์ ๊ณ์ฝ ๋ถ์ผ์น๋ฅผ ๋ฐ๋ณต์ ์ผ๋ก ๋ง์ถ๊ณ ์ถ์ ๋ ์ฌ์ฉํ์ธ์. (๊ตฌ๋ถ: openapi.yaml ์์ฒด๋ฅผ lintํ๊ณ ๋ผ์ฐํธ ํธ๋ค๋ฌ์ ๋๊ธฐํํ๋ ๊ฑด looping:openapi-sync-until-valid, READMEยทAPI ๋ ํผ๋ฐ์ค ๋ฑ ๋ฌธ์๋ฅผ ์ฝ๋์ ๋ง์ถ๋ ๊ฑด looping:docs-sync-after-edits, spec.md ์ฒดํฌ๋ฆฌ์คํธ๋๋ก ์ ๊ท ๊ธฐ๋ฅ์ ๊ตฌํํ๋ ๊ฑด looping:spec-first-ship, ์ ์ฒด ํ ์คํธ ์ค์ํธ๋ฅผ green๊น์ง ๋๋ฆฌ๋ ๊ฑด looping:test-until-green)
์คํจํ๋ ํ ์คํธ๋ฅผ ๋จผ์ ์ฐ๊ณ โ ํต๊ณผ์ํฌ ์ต์ํ์ ์ฝ๋๋ฅผ ๊ตฌํํ๊ณ โ ๋ฆฌํฉํฐํ๋ red-green-refactor TDD ์ฌ์ดํด์, ๋์ ๋์์ด ํ ์คํธ๋ก ์์ ํ ๋ฎ์ด๊ณ ์ ์ฒด ์ค์ํธ๊ฐ ํต๊ณผํ ๋๊น์ง ์๋์ผ๋ก ๋ฐ๋ณตํ๋ ๋ซํ ๋ฃจํ์ ๋๋ค. ์ฌ์ฉ์๊ฐ "TDD๋ก ๋ง๋ค์ด์ค", "ํ ์คํธ ๋จผ์ ์ฐ๊ณ ๊ตฌํํด์ค", "red-green-refactor๋ก ๋๋ ค์ค", "์คํจ ํ ์คํธ๋ถํฐ ์์ฑํด์ ๊ธฐ๋ฅ ์ถ๊ฐํด์ค", "ํ ์คํธ ์ฃผ๋๋ก ์ด ๊ธฐ๋ฅ ๊ตฌํํด์ค", "Autoloop TDD", "test-first loop", "write a failing test then implement", "TDD this feature"์ฒ๋ผ ํ ์คํธ๋ฅผ ๋จผ์ ์์ฑํด ์ ๊ธฐ๋ฅ์ ๊ตฌํํ๊ณ ์ถ์ ๋ ์ฌ์ฉํ์ธ์. (๊ตฌ๋ถ: ์ด๋ฏธ ๊นจ์ง ๊ธฐ์กด ํ ์คํธ๋ฅผ ํต๊ณผ์ํค๋ ๊ฑด looping:test-until-green, ์ปค๋ฒ๋ฆฌ์ง %๋ฅผ ์ฑ์ฐ๋ ค๊ณ ํ ์คํธ๋ง ์ถ๊ฐํ๋ ๊ฑด looping:coverage-until-threshold, spec.md ์ฒดํฌ๋ฆฌ์คํธ๋ก ์๊ตฌ์ฌํญ์ ํ๋์ฉ ๊ตฌํํ๋ ๊ฑด looping:spec-first-ship, E2E ์ค์ํธ๋ฅผ green์ผ๋ก ๋ง๋๋ ๊ฑด looping:e2e-until-green)
ํ๋ก๋์ ๋น๋๋ฅผ ์ค์ ๋ก ๋๋ ค ์ปดํ์ผยทํ์ ยท๋ฒ๋ค๋ง ์๋ฌ๋ฅผ ํ ๋ฒ์ ํ๋์ฉ ๊ณ ์น๊ณ , ๋น๋๊ฐ ์ข ๋ฃ ์ฝ๋ 0์ผ๋ก ์ฑ๊ณตํ ๋๊น์ง ์๋์ผ๋ก ๋ฐ๋ณตํ๋ ๋ซํ ๋ฃจํ์ ๋๋ค. ์ฌ์ฉ์๊ฐ "๋น๋ ํต๊ณผํ ๋๊น์ง ๋๋ ค์ค", "๋น๋ ์๋ฌ ๋ค ๊ณ ์ณ์ค", "๋น๋ ๊นจ์ง ๊ฑฐ green ๋ ๋๊น์ง", "ํ๋ก๋์ ๋น๋ ์ฑ๊ณต์์ผ์ค", "npm run build ํต๊ณผํ๊ฒ", "build until green", "fix build errors until it compiles", "make the production build pass"์ฒ๋ผ ์์ฒญํ๊ฑฐ๋, ๋น๋๊ฐ ๊นจ์ง ๊ฑธ ๋ฐ๋ณต์ ์ผ๋ก ๊ณ ์ณ ์ฑ๊ณต์ํค๊ณ ์ถ์ ๋ ์ฌ์ฉํ์ธ์. (๊ตฌ๋ถ: ํ ์คํธ ์ค์ํธ ์คํจ๋ฅผ ๊ณ ์น๋ ๊ฑด looping:test-until-green, lintยทํ์ ์ฒดํฌ ์๋ฌ ์ ๋ฆฌ๋ looping:lint-typecheck-fix, ์๊ฒฉ CI ๋น๋ ์คํจ ๊ฐ์๋ looping:ci-failure-watcher, ๋ฒ๋ค ์ฌ์ด์ฆ ์์ฐ ์ด๊ณผ๋ looping:bundle-size-budget)
ํ๋ก๋์ ๋น๋๋ฅผ ๋๋ ค ํด๋ผ์ด์ธํธ ๋ฒ๋ค ํฌ๊ธฐ๋ฅผ ์ธก์ ํ๊ณ , ์ค์ ํ size-limit ์์ฐ์ ๋์ผ๋ฉด ๋ฌด๊ฑฐ์ด ๋ชจ๋ dynamic importยท๋ฏธ์ฌ์ฉ ์์กด์ฑ ์ ๊ฑฐยท๋ผ์ฐํธ ๋ถํ ๋ก ๋ค์ด์ดํธํ ๋ค size-limit์ด ์ข ๋ฃ ์ฝ๋ 0์ผ๋ก ํต๊ณผํ ๋๊น์ง ์๋์ผ๋ก ๋ฐ๋ณตํ๋ ๋ซํ ๋ฃจํ์ ๋๋ค. ์ฌ์ฉ์๊ฐ "๋ฒ๋ค ํฌ๊ธฐ ์ค์ฌ์ค", "๋ฒ๋ค ์์ฐ ์ ๋๊ฒ ํด์ค", "size-limit ํต๊ณผ์์ผ์ค", "๋ฒ๋ค ๋ค์ด์ดํธํด์ค", "client bundle ๊ฐ๋ณ๊ฒ ์ ์งํด์ค", "bundle size budget", "keep the client bundle under budget", "loop until size-limit passes"์ฒ๋ผ ํด๋ผ์ด์ธํธ ๋ฒ๋ค์ ์์ฐ ์ดํ๋ก ๋์ด๋ด๋ฆฌ๊ณ ์ถ์ ๋ ์ฌ์ฉํ์ธ์. (๊ตฌ๋ถ: ๋น๋ ์์ฒด๋ฅผ ์ฑ๊ณต์ํค๋ ๊ฑด looping:build-until-green, ์ฃฝ์ exportยท๋ฏธ์ฌ์ฉ ํ์ผยท๊ณ ์ ์์กด์ฑ ์ ๋ฆฌ๋ looping:knip-until-clean, ์์กด์ฑ์ ํ๋์ฉ ์์ ํ๊ฒ ์ ๊ทธ๋ ์ด๋ํ๋ ๊ฑด looping:dependency-upgrade-one-by-one)
๊ธฐ๋ฅ์ ์ถ์(ship)ํ ์งํ, ๋ง์ง๋ง ํ๊ทธ ์ดํ์ ์ปค๋ฐ์ ํ์ด CHANGELOG.md์ [Unreleased] ์น์ ์ ์ฌ์ฉ์ ๊ด์ ํญ๋ชฉ์ ์ฑ์ฐ๊ณ conventional commits๋ฅผ ๋ฐ์ํ ๋๊น์ง ๋ฐ๋ณตํ๋ ์๋ ๋ฃจํ์ ๋๋ค. ์ฌ์ฉ์๊ฐ "์ฒด์ธ์ง๋ก๊ทธ ์ ๋ฐ์ดํธํด์ค", "๋ฐฉ๊ธ ์ถ์ํ ๊ฑฐ CHANGELOG์ ๋ฐ์ํด์ค", "๋ฆด๋ฆฌ์ค ๋ ธํธ ์ ๋ฆฌํด์ค", "CHANGELOG ๋๊ธฐํ", "changelog sync after ship", "update the changelog for this release", "sync CHANGELOG after shipping"์ฒ๋ผ ์ถ์ยท๋จธ์ง ์งํ ๋ณ๊ฒฝ ์ด๋ ฅ์ ์ฌ์ฉ์ ์นํ์ ์ผ๋ก ์ ๋ฆฌํ๊ณ ์ถ์ ๋ ์ฌ์ฉํ์ธ์. (๊ตฌ๋ถ: READMEยทAPI ๋ ํผ๋ฐ์คยท์ฃผ์ ๋ฑ ์ผ๋ฐ ๋ฌธ์ ๋๊ธฐํ๋ looping:docs-sync-after-edits, openapi.yaml ์คํ ๋๊ธฐํ๋ looping:openapi-sync-until-valid, API ์๋ต์ด ๊ณ์ฝ๊ณผ ๋ง๋์ง ๊ฒ์ฆ์ looping:api-contract-until-match, ์์ฑํ spec.md ์ฒดํฌ๋ฆฌ์คํธ๋๋ก ๊ตฌํ์ looping:spec-first-ship)
์๊ฒฉ CI๋ฅผ ์ผ์ ๊ฐ๊ฒฉ(๊ธฐ๋ณธ 5๋ถ)๋ง๋ค ํด๋งํด์, ์ฒดํฌ๊ฐ ๋นจ๊ฐ์ง๋ฉด(red) ์คํจ๋ฅผ ์กฐ์ฌํ๊ณ , green์ด ๋ ๋๊น์ง ์์ ์ push ํ๋ ์ธํฐ๋ฒ ๋ฃจํ์ ๋๋ค. ์ฌ์ฉ์๊ฐ "CI ๋นจ๊ฐ๋ถ ๋จ๋ฉด ์๋์ผ๋ก ๊ณ ์ณ์ค", "CI 5๋ถ๋ง๋ค ๊ฐ์ํ๋ค ๊นจ์ง๋ฉด ์์ ", "CI ์ด๋ก ๋ ๋๊น์ง ์ง์ผ๋ด", "gh run ํด๋งํด์ ์คํจ ์ถ์ ยท์์ ", "watch CI", "CI failure watcher", "poll CI until green", "investigate CI failures and push fixes"์ฒ๋ผ ์๊ฒฉ CI ์ํ๋ฅผ ์ฃผ๊ธฐ์ ์ผ๋ก ๊ฐ์ํ๋ค๊ฐ ์คํจ๋ฅผ ์๋์ผ๋ก ์ถ์ ยท์์ ํ๊ณ ์ถ์ ๋ ์ฌ์ฉํ์ธ์. (๊ตฌ๋ถ: ์ฌ๋์ด ์ง์ ํ ๋ฒ ๋๋ฆฌ๋ CI ์์ ์ looping:fix-ci-until-green, ์ฌ๋ฌ PR์ ์ฃผ๊ธฐ์ ์ผ๋ก ๋๋ณด๋ ๊ฑด looping:pr-babysitter, ๋ฐฐํฌ ํ ํฌ์คยท์ค๋ชจํฌ ์๋ํฌ์ธํธ ๊ฐ์๋ looping:deploy-verification-loop, ๋ก์ปฌ ํ๋ก๋์ ๋น๋ ํต๊ณผ๋ looping:build-until-green)
ํ ์คํธ๋ฅผ ์ถ๊ฐํด ์ฝ๋ ์ปค๋ฒ๋ฆฌ์ง(coverage)๋ฅผ ๋ชฉํ ์๊ณ์น(์: 80%)๊น์ง ๋์ด์ฌ๋ฆฌ๋ ๋ซํ ๋ฃจํ์ ๋๋ค. ํ๋ก๋์ ๋์์ ๋ถํ์ํ๊ฒ ๋ฐ๊พธ์ง ์๊ณ , ์ปค๋ฒ๋์ง ์์ ๋ถ๊ธฐ์๋ง ์ง์ค ํ ์คํธ๋ฅผ ๋ํด "์๊ณ์น ์ถฉ์กฑ + ์ ์ฒด ํ ์คํธ ํต๊ณผ(์ข ๋ฃ ์ฝ๋ 0)"์ ์๋ ด์ํต๋๋ค. ์ฌ์ฉ์๊ฐ "์ปค๋ฒ๋ฆฌ์ง 80%๊น์ง ์ฌ๋ ค์ค", "ํ ์คํธ ์ปค๋ฒ๋ฆฌ์ง ๋์ด์ฌ๋ ค์ค", "์ปค๋ฒ๋ฆฌ์ง ์๊ณ์น ์ฑ์์ค", "์ ๋ฎ์ธ ์ฝ๋์ ํ ์คํธ ์ถ๊ฐํด์ค", "coverage until threshold", "raise test coverage to 80%", "add tests until coverage passes"์ฒ๋ผ ์ปค๋ฒ๋ฆฌ์ง ๋ชฉํ๋ฅผ ์ฑ์ฐ๊ณ ์ถ์ ๋ ์ฌ์ฉํ์ธ์. (๊ตฌ๋ถ: ๊ทธ๋ฅ ๊นจ์ง ํ ์คํธ๋ฅผ ํต๊ณผ์ํค๋ ๊ฑด looping:test-until-green, ์คํจ ํ ์คํธ๋ฅผ ๋จผ์ ์ฐ๋ TDD ์ฌ์ดํด์ looping:autoloop-tdd, ๋ถ์์ ยท๊ฐํ ์คํจ ๋ถ๋ฅ๋ looping:flaky-test-triage, e2e ์ค์ํธ ํต๊ณผ๋ looping:e2e-until-green)