JavaScript ์ •์  ๋ถ„์„ ๋„๊ตฌ

JavaScript ์ •์  ์ฝ”๋“œ ๋ถ„์„: ESLint, TypeScript, Semgrep ๋ฐ ๋ณด์•ˆ ์Šค์บ”์— ๋Œ€ํ•œ ์‹ค์šฉ ๊ฐ€์ด๋“œ

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ๋ธŒ๋ผ์šฐ์ €, Node.js๋ฅผ ํ†ตํ•œ ์„œ๋ฒ„, React Native๋ฅผ ํ†ตํ•œ ๋ชจ๋ฐ”์ผ ์•ฑ, ํด๋ผ์šฐ๋“œ ํ•จ์ˆ˜, ์—ฃ์ง€ ์ปดํ“จํŒ… ํ™˜๊ฒฝ ๋“ฑ ์–ด๋””์—์„œ๋‚˜ ์‹คํ–‰๋˜๋Š” ์œ ์ผํ•œ ์–ธ์–ด์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด๋Ÿฌํ•œ ๋ณดํŽธ์„ฑ์—๋Š” ํ’ˆ์งˆ ์ €ํ•˜๋ผ๋Š” ๋Œ€๊ฐ€๊ฐ€ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ๋™์  ํƒ€์ดํ•‘, ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ, ๋น„๋™๊ธฐ ์‹คํ–‰ ๋ชจ๋ธ ๋•๋ถ„์— ์ •์ƒ์ ์ธ ์ƒํ™ฉ์—์„œ๋Š” ์ž˜ ์ž‘๋™ํ•˜๊ณ , ์ƒํ™ฉ์ด ๋ณ€ํ•  ๋•Œ๋Š” ๋ฏธ๋ฌ˜ํ•œ ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋Š” ์ฝ”๋“œ๋ฅผ ์‰ฝ๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. TypeScript๋Š” ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐ ํฐ ๋„์›€์ด ๋˜์ง€๋งŒ, ํƒ€์ž… ์•ˆ์ •์„ฑ์ด ๊ณง ์ฝ”๋“œ ํ’ˆ์งˆ, ๋ณด์•ˆ ๋˜๋Š” ์•„ํ‚คํ…์ฒ˜ ๊ฑด์ „์„ฑ๊ณผ ๊ฐ™์€ ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. ๋ฐ”๋กœ ์ด ๊ฐ„๊ทน์„ ์ •์  ๋ถ„์„์ด ๋ฉ”์›Œ์ค๋‹ˆ๋‹ค.

JavaScript ๋˜๋Š” TypeScript ํ”„๋กœ์ ํŠธ์— ์ ํ•ฉํ•œ ์ •์  ๋ถ„์„ ๋„๊ตฌ ์กฐํ•ฉ์„ ์„ ํƒํ•˜๋Š” ๊ฒƒ์€ ๊ฐ„๋‹จํ•œ ๊ฒฐ์ •์ด ์•„๋‹™๋‹ˆ๋‹ค. ๋ฆฐํŒ…, ๋ณด์•ˆ ๊ฒ€์‚ฌ, ํƒ€์ž… ๊ฒ€์‚ฌ, ๋ฐ๋“œ ์ฝ”๋“œ ๊ฐ์ง€, ์•„ํ‚คํ…์ฒ˜ ๋ถ„์„์€ ๊ฐ๊ฐ ๋‹ค๋ฅธ ๋„๊ตฌ ๋ฒ”์ฃผ์—์„œ ๋‹ค๋ฃจ๋Š” ๋ณ„๊ฐœ์˜ ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค. ๋ณด์•ˆ ์Šค์บ๋„ˆ๊ฐ€ ํ•„์š”ํ•œ ๊ณณ์— ๋ฆฐํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜, ์˜์กด์„ฑ ๋ถ„์„์ด ํ•„์š”ํ•œ ๊ณณ์— ํƒ€์ž… ๊ฒ€์‚ฌ๋งŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๋ถˆ์™„์ „ํ•œ ๋ถ„์„ ๊ฒฐ๊ณผ๋ฅผ ์ดˆ๋ž˜ํ•˜๊ณ  ์ž˜๋ชป๋œ ํ™•์‹ ์„ ์‹ฌ์–ด์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฐ€์ด๋“œ์—์„œ๋Š” ๊ฐ ๋„๊ตฌ๊ฐ€ ์‹ค์ œ๋กœ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ธฐ๋Šฅ๋ณ„๋กœ ์ •๋ฆฌํ•˜์—ฌ, ํŒ€์—์„œ ์ค‘๋ณต ์—†์ด ๋ชจ๋“  ํ’ˆ์งˆ ์ธก๋ฉด์„ ํฌ๊ด„ํ•˜๋Š” ๋„๊ตฌ ์Šคํƒ์„ ๊ตฌ์ถ•ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋•์Šต๋‹ˆ๋‹ค.

์ฐจ๋ก€

๋ฐฉ๋ฒ• SMART TS XL ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ ๊ทœ๋ชจ์—์„œ JavaScript ์ •์  ๋ถ„์„์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

์ด ๊ฐ€์ด๋“œ์—์„œ ๋‹ค๋ฃจ๋Š” ๋ชจ๋“  ๋„๊ตฌ๋Š” JavaScript ๊ฒฝ๊ณ„ ๋‚ด์—์„œ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ESLint๋Š” JavaScript ํŒŒ์ผ์„ ๋ถ„์„ํ•˜๊ณ , TypeScript๋Š” TypeScript ํ”„๋กœ์ ํŠธ ๋‚ด์˜ ํƒ€์ž…์„ ๊ฒ€์‚ฌํ•˜๋ฉฐ, Semgrep์€ JavaScript ๋ฐ TypeScript ์†Œ์Šค ์ฝ”๋“œ์—์„œ ์ทจ์•ฝ์  ํŒจํ„ด์„ ์Šค์บ”ํ•˜๊ณ , SonarQube๋Š” JavaScript ์ฝ”๋“œ๋ฒ ์ด์Šค ์ „๋ฐ˜์˜ ํ’ˆ์งˆ ์ง€ํ‘œ๋ฅผ ์ถ”์ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋„๊ตฌ๋“ค์€ JavaScript ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๊ฒฝ๊ณ„๋ฅผ ๋„˜์–ด ํ•ด๋‹น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์˜์กดํ•˜๋Š” ์‹œ์Šคํ…œ์ด๋‚˜ ๊ทธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์˜์กดํ•˜๋Š” ์‹œ์Šคํ…œ์„ ๋“ค์—ฌ๋‹ค๋ณผ ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค.

SMART TS XL ์ •์  ๋ถ„์„์€ ์ •๋ฐ˜๋Œ€ ๋ฐฉํ–ฅ์—์„œ ์ ‘๊ทผํ•ฉ๋‹ˆ๋‹ค. ์ „์ฒด ์‹œ์Šคํ…œ์—์„œ ์‹œ์ž‘ํ•˜์—ฌ ๊ตฌ์„ฑ ์š”์†Œ ์ˆ˜์ค€๊นŒ์ง€ ๊ตฌ์ถ•ํ•ด ๋‚˜๊ฐ‘๋‹ˆ๋‹ค. JavaScript์˜ ๊ฒฝ์šฐ, ์ด๋Š” JavaScript ๋ฐ TypeScript ์†Œ์Šค ์ฝ”๋“œ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ COBOL, JCL, Java, Python, RPG, PL/I, SQL ๋“ฑ ํ™˜๊ฒฝ์— ์žˆ๋Š” ๋‹ค๋ฅธ ๋ชจ๋“  ์–ธ์–ด์˜ ์†Œ์Šค ์ฝ”๋“œ๋ฅผ ์ˆ˜์ง‘ํ•˜์—ฌ ๋ชจ๋“  ์–ธ์–ด ๊ฐ„์˜ ๊ตฌ์กฐ์  ๊ด€๊ณ„๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ํ†ตํ•ฉ๋œ ์ƒํ˜ธ ์ฐธ์กฐ ๋ชจ๋ธ์„ ๊ตฌ์ถ•ํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, JavaScript ๋ชจ๋“ˆ์ด REST API๋ฅผ ํ˜ธ์ถœํ•˜๊ณ , ํ•ด๋‹น API๋Š” Java ์„œ๋น„์Šค๋กœ ์ง€์›๋˜๋ฉฐ, ์ด ์„œ๋น„์Šค๋Š” COBOL ๋ฐฐ์น˜ ํ”„๋กœ๊ทธ๋žจ์œผ๋กœ ์ฑ„์›Œ์ง„ DB2 ํ…Œ์ด๋ธ”์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด์˜ต๋‹ˆ๋‹ค. SMART TS XL ์ด ๊ทธ๋ฆผ์€ ๋„ค ๊ฐœ์˜ ๋ ˆ์ด์–ด์™€ ๊ทธ ๋ ˆ์ด์–ด๋“ค ์‚ฌ์ด์˜ ์—ฐ๊ฒฐ ๊ด€๊ณ„๋ฅผ ๋ชจ๋‘ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ธฐ๋ฐ˜์˜ ์–ด๋–ค ๋„๊ตฌ๋„ ์ด๋Ÿฌํ•œ ๊ทธ๋ฆผ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

ํŠนํžˆ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐœ๋ฐœํŒ€์˜ ๊ฒฝ์šฐ, SMART TS XL ๋ณดํ‘ธ๋ผ๊ธฐ ๊ฒ€์‚ฌ ๋ฐ ๋ณด์•ˆ ๊ฒ€์‚ฌ ๊ธฐ๋Šฅ์„ ๋ณด์™„ํ•˜๋Š” ์—ฌ๋Ÿฌ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์–ธ์–ด ๊ฐ„ ์˜ํ–ฅ ๋ถ„์„. ๊ธฐ์—…์šฉ API๋ฅผ ์‚ฌ์šฉํ•˜๋Š” JavaScript ๋ชจ๋“ˆ์„ ์ˆ˜์ •ํ•˜๊ธฐ ์ „์—, SMART TS XL์˜ ์˜ํ–ฅ ๋ถ„์„ ์ด ๊ธฐ๋Šฅ์€ ๋‹ค๋ฅธ ์–ธ์–ด๋กœ ์ž‘์„ฑ๋œ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ํฌํ•จํ•˜์—ฌ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์˜ ์˜ํ–ฅ์„ ๋ฐ›๋Š” ์‹œ์Šคํ…œ ๋‚ด์˜ ๋ชจ๋“  ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์‹๋ณ„ํ•ฉ๋‹ˆ๋‹ค. ํŒ€์€ ๋ณ€๊ฒฝ์ด ์‹คํ–‰๋˜๊ธฐ ์ „์— ๋ณ€๊ฒฝ์˜ ์‹ค์ œ ๋ฒ”์œ„๋ฅผ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ ํ›„์— ํŒŒ์•…ํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์‹œ์Šคํ…œ ์ˆ˜์ค€์—์„œ์˜ ๋ฐ๋“œ ์ฝ”๋“œ ๋ฐ ๋„๋‹ฌ ๊ฐ€๋Šฅ์„ฑ ๋ถ„์„. Knip๊ณผ ts-prune์ด JavaScript ํ”„๋กœ์ ํŠธ ๋‚ด์—์„œ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ๋‚ด๋ณด๋‚ด๊ธฐ๋ฅผ ์ฐพ๋Š” ์œ„์น˜, SMART TS XL ์ด ๋„๊ตฌ๋Š” ์‹œ์Šคํ…œ ๋‚ด ์–ด๋””์—์„œ๋„ ํ˜ธ์ถœ๋˜์ง€ ์•Š๋Š” JavaScript ํ•จ์ˆ˜ ๋ฐ ๋ชจ๋“ˆ์„ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—๋Š” Java ์„œ๋น„์Šค, ๋ฐฑ์—”๋“œ API ๋˜๋Š” ๋ฉ”์ธํ”„๋ ˆ์ž„ ํ”„๋กœ๊ทธ๋žจ์˜ ํ˜ธ์ถœ๋„ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์‹œ์Šคํ…œ ์ˆ˜์ค€์˜ ๋ฐ๋“œ ์ฝ”๋“œ ๋ถ„์„์€ JavaScript ํ”„๋ŸฐํŠธ์—”๋“œ๊ฐ€ ๋‹ค๋ฅธ ์–ธ์–ด๋กœ ์ž‘์„ฑ๋œ ๋ฐฑ์—”๋“œ์™€ ๊ธด๋ฐ€ํ•˜๊ฒŒ ํ†ตํ•ฉ๋œ ์กฐ์ง์—์„œ ํŠนํžˆ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

์–ธ์–ด ๊ฒฝ๊ณ„๋ฅผ ๋„˜๋‚˜๋“œ๋Š” ์˜์กด์„ฑ ์‹œ๊ฐํ™”. SMART TS XL์˜ ์ฝ”๋“œ ์‹œ๊ฐํ™” ์ด ๋„๊ตฌ๋Š” JavaScript ๋ชจ๋“ˆ์ด Java ์„œ๋น„์Šค, COBOL ํ”„๋กœ๊ทธ๋žจ, ๊ณต์œ  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ฐ ์™ธ๋ถ€ API์— ์–ด๋–ป๊ฒŒ ์—ฐ๊ฒฐ๋˜๋Š”์ง€ ๋ณด์—ฌ์ฃผ๋Š” ์ข…์†์„ฑ ๋งต์„ ์ƒ์„ฑํ•˜๋ฉฐ, ์–ธ์–ด๋ณ„ ๊ฐœ๋ณ„ ๋ณด๊ธฐ ๋Œ€์‹  ํƒ์ƒ‰ ๊ฐ€๋Šฅํ•œ ๋‹จ์ผ ๋‹ค์ด์–ด๊ทธ๋žจ์œผ๋กœ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์ด๊ธฐ์ข… ์Šคํƒ์„ ์œ„ํ•œ ํ†ตํ•ฉ ํ’ˆ์งˆ ์ธก์ • ๊ธฐ์ค€. ์ฝ”๋“œ ํ’ˆ์งˆ ์ง€ํ‘œ๋ฅผ ๊ฒฝ์˜์ง„์ด๋‚˜ ๊ทœ์ • ์ค€์ˆ˜ ํŒ€์— ๋ณด๊ณ ํ•˜๋Š” ์กฐ์ง์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ณ„์ธต๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ „์ฒด ์Šคํƒ์„ ํฌ๊ด„ํ•˜๋Š” ์ง€ํ‘œ๋ฅผ ํ™œ์šฉํ•˜๋ฉด ์ด์ ์„ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. SMART TS XL์˜ ์ •์  ์ฝ”๋“œ ๋ถ„์„ ์ด ํ‰๊ฐ€ ๊ธฐ์ค€์€ JavaScript์™€ TypeScript๋ฅผ ๋™์ผํ•œ ํ’ˆ์งˆ ๊ธฐ์ค€(์ˆœํ™˜ ๋ณต์žก๋„, ์œ ์ง€๋ณด์ˆ˜์„ฑ ์ง€์ˆ˜, ์˜์กด์„ฑ ๊ฒฐํ•ฉ๋„)์œผ๋กœ ํ‰๊ฐ€ํ•˜๋ฉฐ, ํ™˜๊ฒฝ ๋‚ด ๋ชจ๋“  ์–ธ์–ด์— ์ผ๊ด€๋˜๊ฒŒ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค.

๋…๋ฆฝ์ ์œผ๋กœ JavaScript ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœํ•˜๋Š” ํŒ€์˜ ๊ฒฝ์šฐ, ์ด ๊ฐ€์ด๋“œ์— ์†Œ๊ฐœ๋œ ์˜คํ”ˆ ์†Œ์Šค ๋ฐ ์ƒ์šฉ ๋„๊ตฌ๋Š” ํฌ๊ด„์ ์ธ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๋” ํฐ ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ ์‹œ์Šคํ…œ์˜ ๊ตฌ์„ฑ ์š”์†Œ๋กœ JavaScript ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœํ•˜๋Š” ํŒ€์˜ ๊ฒฝ์šฐ, SMART TS XL ์ด๋Š” ํŒŒ์ผ ์ˆ˜์ค€์ด ์•„๋‹Œ ์‹œ์Šคํ…œ ์ˆ˜์ค€์—์„œ ๋‚˜๋จธ์ง€ ๋ถ„์„์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ์•„ํ‚คํ…์ฒ˜ ๊ฐ€์‹œ์„ฑ ๊ณ„์ธต์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

๋จผ์ง€ ๋ถ„์„๊ณผ ์ •์ „๊ธฐ ๋ถ„์„์˜ ์ฐจ์ด์ ์€ ๋ฌด์—‡์ผ๊นŒ์š”?

์ด ์šฉ์–ด๋“ค์€ ์ข…์ข… ํ˜ผ์šฉ๋˜์ง€๋งŒ, ์„œ๋กœ ๋‹ค๋ฅธ ์ˆ˜์ค€์˜ ๋ถ„์„์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ตฌ๋ถ„์€ ๋„๊ตฌ ์„ ํƒ์— ์žˆ์–ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

๋ณดํ’€ ์Šคํƒ€์ผ ์ผ๊ด€์„ฑ, ์ผ๋ฐ˜์ ์ธ ์˜ค๋ฅ˜ ํŒจํ„ด ๋ฐ ์ฝ”๋”ฉ ๊ทœ์น™ ์ค€์ˆ˜์— ์ค‘์ ์„ ๋‘” ์ •์  ๋ถ„์„์˜ ํ•˜์œ„ ์ง‘ํ•ฉ์ž…๋‹ˆ๋‹ค. ๋ฆฐํ„ฐ๋Š” ์†Œ์Šค ์ฝ”๋“œ๋ฅผ ์ฝ๊ณ  ์ •์˜๋œ ๊ทœ์น™ ์ง‘ํ•ฉ์—์„œ ๋ฒ—์–ด๋‚œ ๋ถ€๋ถ„์„ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค. ESLint๋Š” ๋ฆฐํ„ฐ์˜ ํ•œ ์ข…๋ฅ˜์ด๋ฉฐ, Biome์€ ๋ฆฐํ„ฐ ํฌ๋งทํ„ฐ์ž…๋‹ˆ๋‹ค. ์ด๋“ค์€ ์Šคํƒ€์ผ ์ผ๊ด€์„ฑ, ์ผ๋ฐ˜์ ์ธ ์˜ค๋ฅ˜ ํŒจํ„ด ๋ฐ ์ฝ”๋”ฉ ๊ทœ์น™ ์ค€์ˆ˜ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. no-unused-vars, no-console์˜ˆ์‚ฐ ๋ฐ prefer-const ์œ„๋ฐ˜ ์‚ฌํ•ญ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ํ•จ์ˆ˜ ํ˜ธ์ถœ ๊ฐ„์˜ ๋ฐ์ดํ„ฐ ํ๋ฆ„์„ ์ถ”์ ํ•˜์ง€ ์•Š์œผ๋ฉฐ SQL ์ธ์ ์…˜๊ณผ ๊ฐ™์€ ๋ณด์•ˆ ์ทจ์•ฝ์ ์„ ์ฐพ์•„๋‚ด์ง€๋„ ์•Š์Šต๋‹ˆ๋‹ค.

๋” ๋„“์€ ์˜๋ฏธ์˜ ์ •์  ๋ถ„์„์€ ๋ฆฐํ„ฐ๊ฐ€ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ชจ๋“  ๊ธฐ๋Šฅ์— ๋”ํ•˜์—ฌ ์ œ์–ด ํ๋ฆ„ ๋ถ„์„, ๋ฐ์ดํ„ฐ ํ๋ฆ„(์˜ค์—ผ) ๋ถ„์„, ํ˜ธ์ถœ ๊ทธ๋ž˜ํ”„ ๊ตฌ์„ฑ, ํƒ€์ž… ์ˆ˜์ค€ ์ถ”๋ก , ํŒŒ์ผ ๋ฐ ๋ชจ๋“ˆ ๊ฐ„์˜ ํ”„๋กœ์‹œ์ € ๊ฐ„ ๋ถ„์„๊ณผ ๊ฐ™์€ ์‹ฌ์ธต์ ์ธ ๋ถ„์„์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. CodeQL, ์˜ค์—ผ ๋ชจ๋“œ๊ฐ€ ์ ์šฉ๋œ Semgrep, SonarQube์™€ ๊ฐ™์€ ๋„๊ตฌ๋Š” ์ด๋Ÿฌํ•œ ํฌ๊ด„์ ์ธ ์˜๋ฏธ์˜ ์ •์  ๋ถ„์„์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋„๊ตฌ๋“ค์€ ๋‹จ์ˆœํžˆ ๋ณ€์ˆ˜๊ฐ€ ์„ ์–ธ๋˜์—ˆ๋Š”์ง€ ์—ฌ๋ถ€๋งŒ์ด ์•„๋‹ˆ๋ผ, ์‹ ๋ขฐํ•  ์ˆ˜ ์—†๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ํ”„๋กœ๊ทธ๋žจ ๋‚ด์—์„œ ์–ด๋–ป๊ฒŒ ์ด๋™ํ•˜๋Š”์ง€ ์ดํ•ดํ•จ์œผ๋กœ์จ ์ทจ์•ฝ์ ์„ ์ฐพ์•„๋ƒ…๋‹ˆ๋‹ค.

์นดํ…Œ๊ณ ๋ฆฌ ์ฐพ๊ธฐ๋Œ€ํ‘œ์ ์ธ ๋„๊ตฌ
๋ณดํ’€์Šคํƒ€์ผ, ๊ด€๋ก€, ํ”ํ•œ ์‹ค์ˆ˜ESLint, Biome, OxcLint, StandardJS
์œ ํ˜• ํ™•์ธํƒ€์ž… ์˜ค๋ฅ˜, ๋ˆ„๋ฝ๋œ ํƒ€์ž…, ํƒ€์ž… ๋ถˆ์ผ์น˜ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ(TSC), typescript-eslint
SAST/๋ณด์•ˆ ์Šค์บ”SQL ์ธ์ ์…˜, XSS, ํ”„๋กœํ† ํƒ€์ž… ์˜ค์—ผ, ๋ถˆ์•ˆ์ •ํ•œ ์ข…์†์„ฑSemgrep, CodeQL, Snyk Code, SonarQube
์ฃฝ์€ ์ฝ”๋“œ ๊ฐ์ง€์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ๋‚ด๋ณด๋‚ด๊ธฐ, ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋Š” ์ฝ”๋“œ, ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ๋ณ€์ˆ˜Knip, ts-prune, ESLint no-unused-vars
๊ฑด์ถ• ๋ถ„์„์˜์กด์„ฑ ๋งคํ•‘, ์˜ํ–ฅ ๋ถ„์„, ํ˜ธ์ถœ ๊ทธ๋ž˜ํ”„SMART TS XL์ฝ”๋“œ์”ฌ, ์†Œ์ŠคํŠธ๋ ˆ์ผ

๋ชจ๋“  ์™„์„ฑ๋„ ๋†’์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ”„๋กœ์ ํŠธ๋Š” ์ตœ์†Œํ•œ ์ฒ˜์Œ ์„ธ ๊ฐ€์ง€ ๋ฒ”์ฃผ๋ฅผ ํฌํ•จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทœ๋ชจ๊ฐ€ ํฌ๊ฑฐ๋‚˜ ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ๊ธ‰ ํ”„๋กœ์ ํŠธ๋Š” ๋‹ค์„ฏ ๊ฐ€์ง€ ๋ฒ”์ฃผ ๋ชจ๋‘๋ฅผ ํฌํ•จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

ESLint: ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋ฆฐํŒ…์„ ์œ„ํ•œ ์—…๊ณ„ ํ‘œ์ค€ ๋„๊ตฌ

ESLint๋Š” ๊ฑฐ์˜ ๋ชจ๋“  JavaScript ํ”„๋กœ์ ํŠธ์— ์„ค์น˜๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. create-react-app, Next.js, Vite ๋ฐ ๋Œ€๋ถ€๋ถ„์˜ ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ ์Šค์บํด๋”ฉ์—์„œ ๊ธฐ๋ณธ ๋ฆฐํ„ฐ๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ํ”Œ๋Ÿฌ๊ทธ์ธ ์ƒํƒœ๊ณ„๋Š” ๋ชจ๋“  ์ฃผ์š” ํ”„๋ ˆ์ž„์›Œํฌ(React, Vue, Angular, Node.js)์™€ ์–ธ์–ด ํ™•์žฅ(TypeScript)์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ESLint๋ฅผ ์ œ๋Œ€๋กœ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์€ JavaScript ๊ฐœ๋ฐœ์˜ ํ•„์ˆ˜ ์กฐ๊ฑด์ž…๋‹ˆ๋‹ค.

์„ธ๊ฒŒ ๋•Œ๋ฆฌ๋‹ค

# Install ESLint
npm init @eslint/config@latest

# Run on the project
npx eslint src/

# Auto-fix fixable issues
npx eslint src/ --fix

ESLint v9 ๋ฐ ํ”Œ๋žซ ์„ค์ •: ESLint v9์ด ์ด์ „ ๋ฒ„์ „์„ ๋Œ€์ฒดํ–ˆ์Šต๋‹ˆ๋‹ค. .eslintrc.* ํ‰๋ฉด์„ ์‚ฌ์šฉํ•œ ๊ตฌ์„ฑ ํ˜•์‹ eslint.config.js ์ด ํŒŒ์ผ์€ ํ˜ธํ™˜์„ฑ์„ ๊นจ๋œจ๋ฆฌ๋Š” ๋ณ€๊ฒฝ ์‚ฌํ•ญ์œผ๋กœ, ๊ธฐ์กด์˜ ๋งŽ์€ ํ”„๋กœ์ ํŠธ์— ์˜ํ–ฅ์„ ๋ฏธ์ณค์Šต๋‹ˆ๋‹ค. ์ƒˆ๋กœ์šด ํ‰๋ฉด ์„ค์ • ํ˜•์‹์€ ๋” ๊ฐ„๊ฒฐํ•˜๋ฉฐ, ๊ณ„์ธต์  ์ƒ์† ์‹œ์Šคํ…œ์„ ์ œ๊ฑฐํ•˜๊ณ  ์„ค์ •์„ ๋ช…์‹œ์ ์œผ๋กœ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.

์ž๋ฐ” ์Šคํฌ๋ฆฝํŠธ

// eslint.config.js (ESLint v9 flat config)
import js from "@eslint/js";
import globals from "globals";
import tseslint from "typescript-eslint";

export default [
  js.configs.recommended,
  ...tseslint.configs.recommended,
  {
    languageOptions: {
      globals: globals.browser,
    },
    rules: {
      "no-unused-vars": "error",
      "no-console": "warn",
      "prefer-const": "error",
    },
  },
];

TypeScript์šฉ ESLint ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค typescript-eslint ์ด ํŒจํ‚ค์ง€๋Š” ๊ธฐ์กด ํŒจํ‚ค์ง€๋ฅผ ๋Œ€์ฒดํ•ฉ๋‹ˆ๋‹ค. @typescript-eslint/eslint-plugin @typescript-eslint/parserTSC์—์„œ ๊ฐ•์ œํ•˜์ง€ ์•Š๋Š” 100๊ฐœ ์ด์ƒ์˜ TypeScript ๊ด€๋ จ ๊ทœ์น™์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์„ธ๊ฒŒ ๋•Œ๋ฆฌ๋‹ค

npm install --save-dev typescript-eslint

ESLint ๋ณด์•ˆ ํ”Œ๋Ÿฌ๊ทธ์ธ ESLint์— ๋ณด์•ˆ ๊ด€๋ จ ๊ทœ์น™์„ ์ถ”๊ฐ€ํ•˜์—ฌ ์‚ฌ์šฉ๊ณผ ๊ฐ™์€ ๋ฌธ์ œ๋ฅผ ํƒ์ง€ํ•ฉ๋‹ˆ๋‹ค. eval()์•ˆ์ „ํ•˜์ง€ ์•Š์€ ์ •๊ทœ ํ‘œํ˜„์‹ ๋ฐ ํ”„๋กœํ† ํƒ€์ž… ์ฃผ์ž…:

์„ธ๊ฒŒ ๋•Œ๋ฆฌ๋‹ค

npm install --save-dev eslint-plugin-security

์ž๋ฐ” ์Šคํฌ๋ฆฝํŠธ

// eslint.config.js
import security from "eslint-plugin-security";
export default [security.configs.recommended];

ESLint๊ฐ€ ๋‹ค๋ฃจ๋Š” ๋‚ด์šฉ์ฝ”๋“œ ์Šคํƒ€์ผ, ํ”ํžˆ ๋ฐœ์ƒํ•˜๋Š” ๋ฒ„๊ทธ (no-undef, no-unused-varsํ”Œ๋Ÿฌ๊ทธ์ธ์„ ํ†ตํ•ด ์•ˆํ‹ฐ ํŒจํ„ด, ํ”„๋ ˆ์ž„์›Œํฌ ๊ทœ์น™ ๋ฐ ๊ธฐ๋ณธ ๋ณด์•ˆ ํŒจํ„ด์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ESLint๊ฐ€ ๋‹ค๋ฃจ์ง€ ์•Š๋Š” ๋‚ด์šฉ : ํ•จ์ˆ˜ ํ˜ธ์ถœ ์ „๋ฐ˜์— ๊ฑธ์นœ ๋ฐ์ดํ„ฐ ํ๋ฆ„/์˜ค์—ผ ๋ถ„์„, ํŒŒ์ผ ๊ฐ„ ์˜ํ–ฅ ๋ถ„์„, ์ข…์†์„ฑ ์ทจ์•ฝ์ , ์•„ํ‚คํ…์ฒ˜ ๋งคํ•‘ ๋˜๋Š” ๋น„๋™๊ธฐ ๊ด€๋ จ ์ทจ์•ฝ์  ํŒจํ„ด.

TypeScript: ์ปดํŒŒ์ผ๋Ÿฌ ์ˆ˜์ค€์—์„œ์˜ ์ •์  ์•ˆ์ „์„ฑ

TypeScript ์ปดํŒŒ์ผ๋Ÿฌ(TSC)๋Š” JavaScript ํ”„๋กœ์ ํŠธ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ€์žฅ ๊ฐ•๋ ฅํ•œ ์ •์  ๋ถ„์„์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, ๋ชจ๋“  ํ•จ์ˆ˜ ๊ฒฝ๊ณ„์—์„œ ์ „์ฒด ์ฝ”๋“œ๋ฒ ์ด์Šค์— ๊ฑธ์ณ ํƒ€์ž… ์ •ํ™•์„ฑ์„ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค. strict ๋ชจ๋“œ tsconfig.json ๊ฐ€์žฅ ๋งŽ์€ ๋ฌธ์ œ๋ฅผ ํฌ์ฐฉํ•ฉ๋‹ˆ๋‹ค:

JSON

{
  "compilerOptions": {
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "exactOptionalPropertyTypes": true
  }
}

noUnusedLocals noUnusedParameters ์ปดํŒŒ์ผ๋Ÿฌ ์ˆ˜์ค€์—์„œ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ๋ณ€์ˆ˜์™€ ํ•จ์ˆ˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ํฌ์ฐฉํ•˜๋ฉฐ, ESLint์˜ ๊ธฐ๋Šฅ๊ณผ ์ผ๋ถ€ ๊ฒน์นฉ๋‹ˆ๋‹ค. no-unused-vars ํ•˜์ง€๋งŒ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ๊ด€๋ จ ํŒจํ„ด์— ๋Œ€ํ•ด์„œ๋Š” ๋” ์ •ํ™•ํ•˜๊ฒŒ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ-eslint TypeScript์˜ ํƒ€์ž… ๊ฒ€์‚ฌ๊ธฐ์™€ ESLint์˜ ๊ทœ์น™ ์‹œ์Šคํ…œ ๊ฐ„์˜ ๊ฐ„๊ทน์„ ๋ฉ”์›Œ์ค๋‹ˆ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ทœ์น™๋“ค์ด ์žˆ์Šต๋‹ˆ๋‹ค. @typescript-eslint/no-floating-promises @typescript-eslint/await-thenable TSC๋‚˜ ESLint๋งŒ์œผ๋กœ๋Š” ์žก์•„๋‚ผ ์ˆ˜ ์—†๋Š” ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์˜ค๋ฅ˜๋ฅผ ๊ฐ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ํƒ€์ž… ์ •๋ณด๋ฅผ ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค.

์ž๋ฐ” ์Šคํฌ๋ฆฝํŠธ

// eslint.config.js -- typescript-eslint with type-checked rules
import tseslint from "typescript-eslint";

export default tseslint.config(
  ...tseslint.configs.strictTypeChecked,
  {
    languageOptions: {
      parserOptions: {
        project: true,  // enables type-aware rules
        tsconfigRootDir: import.meta.dirname,
      },
    },
    rules: {
      "@typescript-eslint/no-floating-promises": "error",
      "@typescript-eslint/await-thenable": "error",
      "@typescript-eslint/no-misused-promises": "error",
    },
  }
);

์ด ์„ธ ๊ฐ€์ง€ ๊ทœ์น™์€ ํŠนํžˆ ์ด ๊ธฐ์‚ฌ์˜ ๊ฒ€์ƒ‰ ์ฝ˜์†” ๋ฐ์ดํ„ฐ์— ๋‚˜ํƒ€๋‚˜๋Š” async/await ์˜ค๋ฅ˜ ํŒจํ„ด์„ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ์ž˜๋ชป๋œ Promise ์ฒ˜๋ฆฌ๋Š” ์ตœ์‹  JavaScript์—์„œ ๊ฐ€์žฅ ํ”ํ•˜๊ฒŒ ๋ฐœ์ƒํ•˜๋Š” ๋ฒ„๊ทธ ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค. typescript-eslint ๋ณ„๋„์˜ ๋„๊ตฌ ์—†์ด๋„ ํฌ์ฐฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Biome๊ณผ OxcLint: ์ฐจ์„ธ๋Œ€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํˆด

ESLint๋Š” 10๋…„ ๋™์•ˆ ๊ธฐ๋ณธ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋ฆฐํ„ฐ์˜€์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด์ œ ๋‘ ๊ฐœ์˜ ์ƒˆ๋กœ์šด ๋„๊ตฌ๊ฐ€ ํ›จ์”ฌ ๋›ฐ์–ด๋‚œ ์„ฑ๋Šฅ์œผ๋กœ ๊ทธ ์ž๋ฆฌ๋ฅผ ์œ„ํ˜‘ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

Biome์€ ESLint์™€ Prettier๋ฅผ ๋ชจ๋‘ ๋Œ€์ฒดํ•˜๋Š” ๋‹จ์ผ ๋„๊ตฌ๋กœ, ๋ฆฐํŒ…, ํฌ๋งทํŒ…, ์ž„ํฌํŠธ ๊ด€๋ฆฌ ๊ธฐ๋Šฅ์„ ํ•˜๋‚˜์˜ ๋ฐ”์ด๋„ˆ๋ฆฌ์— ์ œ๊ณตํ•˜๋ฉฐ ๊ธฐ๋ณธ ์‚ฌ์šฉ์—๋Š” ๋ณ„๋„์˜ ์„ค์ •์ด ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. Rust๋กœ ์ž‘์„ฑ๋˜์—ˆ์œผ๋ฉฐ ๋Œ€๊ทœ๋ชจ ์ฝ”๋“œ๋ฒ ์ด์Šค์—์„œ ESLint๋ณด๋‹ค 25~35๋ฐฐ ๋น ๋ฅธ ์†๋„๋ฅผ ์ž๋ž‘ํ•ฉ๋‹ˆ๋‹ค. Biome์€ JavaScript, TypeScript, JSX, JSON์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

์„ธ๊ฒŒ ๋•Œ๋ฆฌ๋‹ค

# Install
npm install --save-dev --save-exact @biomejs/biome

# Initialize config
npx @biomejs/biome init

# Check (lint + format check)
npx @biomejs/biome check --write src/

OxcLint (Oxc ํ”„๋กœ์ ํŠธ์˜ ์ผ๋ถ€)๋Š” Rust ๊ธฐ๋ฐ˜์˜ ๋˜ ๋‹ค๋ฅธ ๋ฆฐํ„ฐ๋กœ, ESLint์™€ ํ˜ธํ™˜๋˜๋Š” ๊ทœ์น™์„ 50~100๋ฐฐ ๋น ๋ฅธ ์†๋„๋กœ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ESLint์˜ ํ•ต์‹ฌ ๊ทœ์น™์„ ๋Œ€์ฒดํ•˜๋„๋ก ์„ค๊ณ„๋˜์—ˆ์œผ๋ฉฐ, ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๊ณผ์ •์—์„œ ESLint์™€ ํ•จ๊ป˜ ์‹คํ–‰๋˜๋„๋ก ๊ณ ์•ˆ๋˜์—ˆ์œผ๋ฏ€๋กœ, ESLint๋ฅผ ์™„์ „ํžˆ ๊ต์ฒดํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

์„ธ๊ฒŒ ๋•Œ๋ฆฌ๋‹ค

# Install
npm install --save-dev oxlint

# Run
npx oxlint src/

๊ฐ ๋„๊ตฌ๋ฅผ ์–ธ์ œ ์‚ฌ์šฉํ•ด์•ผ ํ• ๊นŒ์š” ? ์ƒˆ๋กœ์šด ํ”„๋กœ์ ํŠธ์˜ ๊ฒฝ์šฐ, Biome์€ ๋ฆฐํŒ… ๋ฐ ํฌ๋งทํŒ…์„ ์œ„ํ•œ ๊ฐ€์žฅ ๊ฐ•๋ ฅํ•œ ๋‹จ์ผ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. ESLint ์„ค์ •๊ณผ ํ”Œ๋Ÿฌ๊ทธ์ธ์ด ๊ด‘๋ฒ”์œ„ํ•˜๊ฒŒ ์ ์šฉ๋œ ๊ธฐ์กด ํ”„๋กœ์ ํŠธ์˜ ๊ฒฝ์šฐ, Biome์œผ๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•˜๋ ค๋ฉด ๊ทœ์น™ ์ ์šฉ ๋ฒ”์œ„๋ฅผ ๊ฒ€์ฆํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. OxcLint๋Š” ํ”Œ๋Ÿฌ๊ทธ์ธ ์ƒํƒœ๊ณ„๋ฅผ ์ฆ‰์‹œ ํฌ๊ธฐํ•  ์ˆ˜ ์—†๋Š” ๋Œ€๊ทœ๋ชจ ๊ธฐ์กด ํ”„๋กœ์ ํŠธ์—์„œ ESLint๋ฅผ ์ ์ง„์ ์œผ๋กœ ๋Œ€์ฒดํ•˜๋Š” ๋ฐ ๋” ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

์ˆ˜๋‹จ์†๋„ vs ESLintPrettier๋ฅผ ๋Œ€์ฒดํ•ฉ๋‹ˆ๋‹ค.ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์ง€์›ํ”Œ๋Ÿฌ๊ทธ์ธ ์ƒํƒœ๊ณ„
ESLint๊ธฐ์ค€์•„๋‹ˆ์š” (Prettier์™€ ์ง์„ ์ด๋ฃจ์„ธ์š”)typescript-eslint๋ฅผ ํ†ตํ•ด๊ฐ€์žฅ ํฐ ๊ทœ๋ชจ (~3,000๊ฐœ ํ”Œ๋Ÿฌ๊ทธ์ธ)
๋ฐ”์ด์˜ค ๋ฉ”25~35๋ฐฐ ๋” ๋น ๋ฆ„๊ฐ€๋Šฅ๋‚ด์žฅ์ œํ•œ์ ์ด์ง€๋งŒ ์„ฑ์žฅ ์ค‘
์˜ฅ์Šฌ๋ฆฐํŠธ50~100๋ฐฐ ๋” ๋น ๋ฆ„์•„๋‹ˆ๋‚ด์žฅESLint ํ˜ธํ™˜ ํ•˜์œ„ ์ง‘ํ•ฉ
์Šคํƒ ๋‹ค๋“œJSESLint์™€ ์œ ์‚ฌํ•จ์ผ๋ถ€์˜์ œํ•œ๋œ๊ณ ์ • ๊ทœ์น™ ์„ธํŠธ

Semgrep: ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋ณด์•ˆ์„ ์œ„ํ•œ ํŒจํ„ด ๊ธฐ๋ฐ˜ SAST

Semgrep์€ ์ฝ”๋“œ ํŒจํ„ด ๋งค์นญ์„ ํ†ตํ•ด ๋ณด์•ˆ ์ทจ์•ฝ์ ์„ ์ฐพ์•„๋‚ด๋Š” ๋‹ค๊ตญ์–ด ์ •์  ๋ถ„์„ ๋ณด์•ˆ ํ…Œ์ŠคํŠธ(SAST) ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. ESLint๊ฐ€ ์Šคํƒ€์ผ๊ณผ ๊ทœ์น™์„ ๊ฐ•์ œํ•˜๋Š” ๋ฐ˜๋ฉด, Semgrep์€ SQL ์ธ์ ์…˜, XSS, ํ”„๋กœํ† ํƒ€์ž… ์˜ค์—ผ, ํ•˜๋“œ์ฝ”๋”ฉ๋œ ์ž๊ฒฉ ์ฆ๋ช…, ์•ˆ์ „ํ•˜์ง€ ์•Š์€ Express.js ๊ตฌ์„ฑ ๋“ฑ JavaScript ๋ฐ TypeScript ์ „๋ฐ˜์— ๊ฑธ์ณ ์ˆ˜๋ฐฑ ๊ฐ€์ง€์˜ ๋ณด์•ˆ ํŒจํ„ด์„ ์ฐพ์•„๋ƒ…๋‹ˆ๋‹ค.

ESLint์™€์˜ ์ฃผ์š” ์ฐจ์ด์ ์€ Semgrep ๊ทœ์น™์ด ๋Œ€์ƒ ์–ธ์–ด์˜ ๊ตฌ๋ฌธ์„ ๋งค์šฐ ์œ ์‚ฌํ•˜๊ฒŒ ๋ฐ˜์˜ํ•˜๋Š” ์ฝ”๋“œ ํŒจํ„ด์œผ๋กœ ์ž‘์„ฑ๋˜์–ด ์ •์  ๋ถ„์„์— ๋Œ€ํ•œ ์ „๋ฌธ ์ง€์‹์ด ์—†๋Š” ๊ฐœ๋ฐœ์ž๋„ ์ฝ๊ณ  ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค.

์–Œ

# Custom Semgrep rule: flag direct use of user input in SQL queries
rules:
  - id: sql-injection-express
    patterns:
      - pattern: |
          $APP.get($ROUTE, ($REQ, $RES) => {
            ...
            $DB.query($REQ.query.$INPUT, ...);
            ...
          })
    message: User input directly used in SQL query -- use parameterized queries
    languages: [javascript, typescript]
    severity: ERROR

์„ธ๊ฒŒ ๋•Œ๋ฆฌ๋‹ค

# Run Semgrep with the community security rule registry
semgrep scan --config=p/javascript src/

# Run with a specific rule set for Node.js
semgrep scan --config=p/nodejs src/

Semgrep๊ณผ ESLint ๋Š” ๊ฒฝ์Ÿ ๊ด€๊ณ„๊ฐ€ ์•„๋‹ˆ๋ผ ์ƒํ˜ธ ๋ณด์™„์ ์ธ ๊ด€๊ณ„์ž…๋‹ˆ๋‹ค. ์ฝ”๋“œ ํ’ˆ์งˆ ๋ฐ ๊ทœ์น™ ์ค€์ˆ˜์—๋Š” ESLint๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , ๋ณด์•ˆ ๊ฒ€์‚ฌ์—๋Š” Semgrep์„ ์‚ฌ์šฉํ•˜์„ธ์š”. ๋Œ€๋ถ€๋ถ„์˜ JavaScript ๊ฐœ๋ฐœํŒ€์€ CI ํ™˜๊ฒฝ์—์„œ ๋‘ ๋„๊ตฌ ๋ชจ๋‘๋ฅผ ์‹คํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. GitLab์€ ์ตœ๊ทผ SAST ๋ถ„์„ ๋„๊ตฌ๋ฅผ ESLint์—์„œ Semgrep์œผ๋กœ ์ „ํ™˜ํ•œ๋‹ค๊ณ  ๋ฐœํ‘œํ–ˆ๋Š”๋ฐ, ๋ณด์•ˆ ๊ฒ€์‚ฌ ๋„๊ตฌ๋กœ์„œ์˜ ESLint๋Š” ๋‹จ๊ณ„์ ์œผ๋กœ ํ์ง€ํ•˜๊ณ  ๋ฆฐํŒ… ๋„๊ตฌ๋กœ๋Š” ์œ ์ง€ํ•  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค. ์ด๋Š” ESLint๊ฐ€ ๋ฆฐํŒ…์— ์ ํ•ฉํ•˜๊ณ  Semgrep์ด ๋ณด์•ˆ ๋ถ„์„์— ์ ํ•ฉํ•˜๋‹ค๋Š” ๊ณต๊ฐ๋Œ€๊ฐ€ ํ˜•์„ฑ๋˜๊ณ  ์žˆ์Œ์„ ๋ฐ˜์˜ํ•ฉ๋‹ˆ๋‹ค.

SonarQube์™€ SonarLint: ์ง€์†์ ์ธ ํ’ˆ์งˆ ๊ด€๋ฆฌ ์‹œ์Šคํ…œ

SonarQube๋Š” ํ’ˆ์งˆ ๊ฒŒ์ดํŠธ ๋ชจ๋ธ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๊ฐ ํ’€ ๋ฆฌํ€˜์ŠคํŠธ๋Š” ์ •์˜๋œ ํ’ˆ์งˆ ํ”„๋กœํŒŒ์ผ์— ๋”ฐ๋ผ ํ‰๊ฐ€๋˜๋ฉฐ, ์ฝ”๋“œ๊ฐ€ ๊ธฐ์ค€์„ ์ถฉ์กฑํ•˜์ง€ ๋ชปํ•˜๋ฉด ๋ณ‘ํ•ฉ์ด ์ฐจ๋‹จ๋ฉ๋‹ˆ๋‹ค. JavaScript ๋ฐ TypeScript์˜ ๊ฒฝ์šฐ ๋ฒ„๊ทธ, ์ฝ”๋“œ ์Šค๋ฉœ, ๋ณด์•ˆ ์ทจ์•ฝ์  ๋ฐ ์ค‘๋ณต์„ ๊ฐ์ง€ํ•˜๊ณ  ์‹œ๊ฐ„ ๊ฒฝ๊ณผ์— ๋”ฐ๋ฅธ ์ถ”์„ธ๋ฅผ ์ถ”์ ํ•ฉ๋‹ˆ๋‹ค.

SonarLint ๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋™์•ˆ SonarQube ๊ทœ์น™์„ ๋กœ์ปฌ์— ํ‘œ์‹œํ•˜์—ฌ CI๋ฅผ ๊ธฐ๋‹ค๋ฆด ํ•„์š” ์—†์ด ์ฆ‰๊ฐ์ ์ธ ํ”ผ๋“œ๋ฐฑ์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” IDE ํ™•์žฅ ํ”„๋กœ๊ทธ๋žจ์ž…๋‹ˆ๋‹ค.

SonarQube๊ฐ€ ์ˆœ์ˆ˜ ๋ฆฐํŒ… ๋„๊ตฌ์™€ ์ฐจ๋ณ„ํ™”๋˜๋Š” ์ ์€ ์ง€์†์ ์ธ ์ธก์ • ๋ชจ๋ธ์ž…๋‹ˆ๋‹ค. SonarQube๋Š” ๊ธฐ์ˆ  ๋ถ€์ฑ„, ์ฝ”๋“œ ์ปค๋ฒ„๋ฆฌ์ง€, ๋ณด์•ˆ ์ทจ์•ฝ์ ์˜ ๋ณ€ํ™”๋ฅผ ์‹œ๊ฐ„ ๊ฒฝ๊ณผ์— ๋”ฐ๋ผ ์ถ”์ ํ•ฉ๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ์ž์šฉ ์ง„๋‹จ ๊ธฐ๋Šฅ๊ณผ ๋”๋ถˆ์–ด ๊ด€๋ฆฌ์ž ์ˆ˜์ค€์˜ ์ฝ”๋“œ ํ’ˆ์งˆ ๋ณด๊ณ ์„œ๊ฐ€ ํ•„์š”ํ•œ ํŒ€์—๊ฒŒ SonarQube๋Š” ์ตœ์ ์˜ ์„ ํƒ์ž…๋‹ˆ๋‹ค.

JavaScript/TypeScript ํ”„๋กœ์ ํŠธ์˜ ์ฃผ์š” ์„ค์ • :

  • ์ƒˆ๋กœ์šด ์ฐจ๋‹จ ์š”์†Œ ๋˜๋Š” ์ค‘์š”ํ•œ ๋ณด์•ˆ ์ทจ์•ฝ์ ์ด ๋ฐœ์ƒํ•  ๊ฒฝ์šฐ ์‹คํŒจํ•˜๋Š” ํ’ˆ์งˆ ๊ฒŒ์ดํŠธ๋ฅผ ์„ค์ •ํ•˜์‹ญ์‹œ์˜ค.
  • ํ™œ์„ฑํ™” Sonar Way ๊ทœ์น™ ํ”„๋กœํ•„์„ ๊ธฐ์ค€์„ ์œผ๋กœ ์‚ฌ์šฉ
  • VS Code ๋˜๋Š” IntelliJ์—์„œ SonarLint์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ฉด ์—๋””ํ„ฐ ๋‚ด์—์„œ ๋ฐ”๋กœ ํ”ผ๋“œ๋ฐฑ์„ ๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • GitHub Actions ๋˜๋Š” GitLab CI์™€ ํ†ตํ•ฉํ•˜๋ ค๋ฉด ๋‹ค์Œ์„ ์‚ฌ์šฉํ•˜์„ธ์š”. SonarQube Scan ๋™์ž‘

CodeQL: ์‹ฌ์ธต์ ์ธ ์ทจ์•ฝ์  ํƒ์ง€๋ฅผ ์œ„ํ•œ ์‹œ๋งจํ‹ฑ ์ฝ”๋“œ ์Šค์บ๋‹

GitHub์—์„œ ๊ฐœ๋ฐœํ•œ CodeQL์€ ์ฝ”๋“œ๋ฅผ ์ฟผ๋ฆฌ ๊ฐ€๋Šฅํ•œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋กœ ๋ณ€ํ™˜ํ•˜๊ณ  ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋Œ€ํ•ด ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ์˜๋ฏธ ๋ถ„์„์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. JavaScript์™€ TypeScript๋ฅผ ์ง€์›ํ•˜๋ฉฐ GitHub Advanced Security๋ฅผ โ€‹โ€‹ํ†ตํ•ด ์˜คํ”ˆ ์†Œ์Šค ํ”„๋กœ์ ํŠธ์—์„œ ๋ฌด๋ฃŒ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

CodeQL์€ ํ”„๋กœ๊ทธ๋žจ ์ „์ฒด์—์„œ ๋ฐ์ดํ„ฐ๊ฐ€ ์–ด๋–ป๊ฒŒ ํ๋ฅด๋Š”์ง€ ์ดํ•ดํ•ด์•ผ ํ•˜๋Š” ์ทจ์•ฝ์ ์„ ์ฐพ์•„๋ƒ…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์‚ฌ์šฉ์ž๊ฐ€ ์ œ์–ดํ•˜๋Š” โ€‹โ€‹๊ฐ’์ด ์—ฌ๋Ÿฌ ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ ๊ฑฐ์ณ ์•ˆ์ „ํ•˜์ง€ ์•Š์€ ์ž‘์—…์— ๋„๋‹ฌํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ ๋ถ„์„ํ•ฉ๋‹ˆ๋‹ค. CodeQL์€ ์ฝ”๋“œ ๊ฒฝ๋กœ๊ฐ€ ๊ฐ„์ ‘์ ์ธ ๊ฒฝ์šฐ Semgrep๊ณผ ๊ฐ™์€ ํŒจํ„ด ๋งค์นญ ๋„๊ตฌ๊ฐ€ ๋†“์น˜๋Š” ์ทจ์•ฝ์ ์„ ์žก์•„๋‚ด๋Š” ๋ฐ ํšจ๊ณผ์ ์ž…๋‹ˆ๋‹ค.

์–Œ

# .github/workflows/codeql.yml
name: CodeQL Analysis
on: [push, pull_request]
jobs:
  analyze:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: github/codeql-action/init@v3
        with:
          languages: javascript-typescript
      - uses: github/codeql-action/autobuild@v3
      - uses: github/codeql-action/analyze@v3

CodeQL์€ Semgrep๋ณด๋‹ค ์„ค์ • ๋น„์šฉ์ด ๋” ๋งŽ์ด ๋“ค๊ณ  ์‹คํ–‰ ์†๋„๋„ ๋А๋ฆฌ์ง€๋งŒ, ํŒจํ„ด ๊ธฐ๋ฐ˜ ๋„๊ตฌ๋กœ๋Š” ์ „์ฒด ๋ฐ์ดํ„ฐ ํ๋ฆ„ ๋ถ„์„ ์—†์ด๋Š” ์‹๋ณ„ํ•  ์ˆ˜ ์—†๋Š” ํ•จ์ˆ˜ ๊ฐ„, ํŒŒ์ผ ๊ฐ„ ์˜ค์—ผ ํ๋ฆ„๊ณผ ๊ฐ™์€ ๋‹ค๋ฅธ ์œ ํ˜•์˜ ์ทจ์•ฝ์ ์„ ํฌ์ฐฉํ•ฉ๋‹ˆ๋‹ค.

์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ์ฝ”๋“œ ๊ฐ์ง€: ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ๋‚ด๋ณด๋‚ด๊ธฐ ๋ฐ ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋Š” ์ฝ”๋“œ

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์™€ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ํ”„๋กœ์ ํŠธ์—์„œ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ์ฝ”๋“œ๋Š” ํŠนํžˆ ๋ฌธ์ œ๊ฐ€ ๋˜๋Š”๋ฐ, ๋ชจ๋“ˆ ์‹œ์Šคํ…œ์ด ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ๋‚ด๋ณด๋‚ด๊ธฐ๊ฐ€ ๋ˆ„์ ๋˜๋Š” ๊ฒƒ์„ ๋ง‰์ง€ ๋ชปํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ํ•จ์ˆ˜๊ฐ€ ๋‚ด๋ณด๋‚ด์กŒ์ง€๋งŒ ํ•œ ๋ฒˆ๋„ ๊ฐ€์ ธ์˜ค์ง€ ์•Š์€ ๊ฒฝ์šฐ, ํŠน๋ณ„ํžˆ ์„ค์ •ํ•˜์ง€ ์•Š์œผ๋ฉด ์–ด๋–ค ํ‘œ์ค€ ๋„๊ตฌ๋„ ์ด์— ๋Œ€ํ•ด ๊ฒฝ๊ณ ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ž๋ฅด๋‹ค ํ˜„์žฌ๋กœ์„œ๋Š” ์ด๋ฅผ ์œ„ํ•œ ๊ฐ€์žฅ ๋›ฐ์–ด๋‚œ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. ์ „์ฒด ํ”„๋กœ์ ํŠธ ๊ทธ๋ž˜ํ”„๋ฅผ ๋ถ„์„ํ•˜์—ฌ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ๋‚ด๋ณด๋‚ด๊ธฐ, ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ์ข…์†์„ฑ ๋“ฑ์„ ์ฐพ์•„๋ƒ…๋‹ˆ๋‹ค. package.json๊ทธ๋ฆฌ๊ณ  ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋Š” ํŒŒ์ผ:

์„ธ๊ฒŒ ๋•Œ๋ฆฌ๋‹ค

npm install --save-dev knip
npx knip

ts-prune์€ ํŠนํžˆ TypeScript๋ฅผ ๋Œ€์ƒ์œผ๋กœ ํ•˜๋ฉฐ, ๊ฐ€์ ธ์˜ค์ง€ ์•Š๋Š” ๋‚ด๋ณด๋‚ธ ์‹ฌ๋ณผ์„ ์ฐพ์•„๋ƒ…๋‹ˆ๋‹ค.

์„ธ๊ฒŒ ๋•Œ๋ฆฌ๋‹ค

npm install --save-dev ts-prune
npx ts-prune

ESLint no-unused-vars @typescript-eslint/no-unused-vars ESLint๋Š” ํŒŒ์ผ ๋‚ด์—์„œ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ์ง€์—ญ ๋ณ€์ˆ˜๋ฅผ ์ฐพ์•„๋‚ผ ์ˆ˜ ์žˆ์ง€๋งŒ, ๋ชจ๋“ˆ ์ˆ˜์ค€์—์„œ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ๋‚ด๋ณด๋‚ด๊ธฐ๋Š” ๊ฐ์ง€ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. Knip์€ ESLint๊ฐ€ ๋†“์น˜๋Š” ๋ถ€๋ถ„์„ ๋ณด์™„ํ•ฉ๋‹ˆ๋‹ค.

์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ์ฝ”๋“œ(๋ฐ๋“œ ์ฝ”๋“œ)๋Š” ํ”„๋ŸฐํŠธ์—”๋“œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ฒˆ๋“ค ํฌ๊ธฐ์— ์ง์ ‘์ ์ธ ์˜ํ–ฅ์„ ๋ฏธ์น˜๊ณ , ์ฝ”๋“œ๋ฒ ์ด์Šค๋ฅผ ๋‹ค๋ฃจ๋Š” ๊ฐœ๋ฐœ์ž์˜ ์ธ์ง€ ๋ถ€ํ•˜๋ฅผ ์ฆ๊ฐ€์‹œํ‚ต๋‹ˆ๋‹ค. ๋ฐ๋“œ ์ฝ”๋“œ ์ œ๊ฑฐ๋Š” ๊ฐ€์žฅ ํšจ๊ณผ์ ์ธ ์œ ์ง€๋ณด์ˆ˜ ํ™œ๋™ ์ค‘ ํ•˜๋‚˜์ด๋ฉฐ, ๋Œ€๊ทœ๋ชจ ์ฝ”๋“œ๋ฒ ์ด์Šค์—์„œ ๋ชจ๋“ˆ ์ˆ˜์ค€์˜ ์‚ฌ์šฉ ๋นˆ๋„๋ฅผ ์‚ฌ๋žŒ์ด ์ง์ ‘ ์ถ”์ ํ•˜๋Š” ๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋„๊ตฌ๋ฅผ ํ†ตํ•ด์„œ๋งŒ ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Async/await ๋ฐ Promise: ์ •์  ๋ถ„์„ ๊ณผ์ œ

์ด ๊ธฐ์‚ฌ์— ๋Œ€ํ•œ ๊ฒ€์ƒ‰ ์ฝ˜์†” ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋ฉด TAJS, Jelly ์ •์  ๋ถ„์„๊ธฐ, SonarJS ๋น„๋™๊ธฐ ๊ทœ์น™ ๋“ฑ๊ณผ ๊ฐ™์€ ๋น„๋™๊ธฐ JavaScript์šฉ ์ •์  ๋ถ„์„ ๋„๊ตฌ์— ๋Œ€ํ•œ ๊ฒ€์ƒ‰์–ด๊ฐ€ ์ƒ๋‹น์ˆ˜ ์ง‘์ค‘๋˜์–ด ์žˆ๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋„๊ตฌ ์‹œ์žฅ์— ์‹ค์ œ๋กœ ๋ถ€์กฑํ•œ ๋ถ€๋ถ„์ด ์žˆ์Œ์„ ๋ฐ˜์˜ํ•ฉ๋‹ˆ๋‹ค.

ํ‘œ์ค€ ๋ฆฐํŒ… ๋„๊ตฌ๋Š” Promise์™€ ๋น„๋™๊ธฐ ํ•จ์ˆ˜๊ฐ€ ์ƒํ˜ธ ์ž‘์šฉํ•˜๋Š” ๋ฐฉ์‹์„ ๋ชจ๋ธ๋งํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ˆ„๋ฝ๋œ ๋ถ€๋ถ„์ด ์žˆ์Šต๋‹ˆ๋‹ค. await์ฒ˜๋ฆฌ๋˜์ง€ ์•Š์€ ๊ฑฐ๋ถ€ ๋˜๋Š” ๋™์‹œ ๋น„๋™๊ธฐ ์ฝ”๋“œ์˜ ๊ฒฝ์Ÿ ์กฐ๊ฑด์€ ๊ตฌ๋ฌธ์ ์œผ๋กœ๋Š” ์œ ํšจํ•ด ๋ณด์ด๊ณ  ๋ชจ๋“  ๋ฆฐํŠธ ๊ทœ์น™์„ ํ†ต๊ณผํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ๊ฐ์ง€ํ•˜๋ ค๋ฉด ๋น„๋™๊ธฐ ์‹คํ–‰ ์˜๋ฏธ๋ก ์„ ๋ชจ๋ธ๋งํ•˜๋Š” ๋„๊ตฌ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

ํ˜„์žฌ์˜ ์‹ค์งˆ์ ์ธ ์ ‘๊ทผ ๋ฐฉ์‹ :

typescript-eslint ๋น„๋™๊ธฐ ๊ด€๋ จ ๊ทœ์น™ ์ค‘ ๊ฐ€์žฅ ์ฆ‰์‹œ ํ™œ์šฉ ๊ฐ€๋Šฅํ•œ ๊ทœ์น™์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์ž๋ฐ” ์Šคํฌ๋ฆฝํŠธ

// Rules that catch common async mistakes
"@typescript-eslint/no-floating-promises": "error",    // await or .catch() required
"@typescript-eslint/await-thenable": "error",          // only await actual Promises
"@typescript-eslint/no-misused-promises": "error",     // Promises in non-async contexts
"@typescript-eslint/require-await": "warn",            // async functions must use await

TAJS(Type Analyzer for JavaScript), Jelly, SAFE์™€ ๊ฐ™์€ ์—ฐ๊ตฌ ๋„๊ตฌ๋Š” Promise ์ฒด์ธ, async/await, ์ด๋ฒคํŠธ ๋ฃจํ”„ ์˜๋ฏธ๋ก ์„ ํฌํ•จํ•œ JavaScript์˜ ๋น„๋™๊ธฐ ์‹คํ–‰ ๋ชจ๋ธ์„ ๋ชจ๋ธ๋งํ•˜๋Š” ํ•™์ˆ ์ ์ธ ์ •์  ๋ถ„์„๊ธฐ์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋„๊ตฌ๋Š” ์‹ค์ œ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๋„๊ตฌ๊ฐ€ ์•„๋‹ˆ๋ผ ์ทจ์•ฝ์  ์—ฐ๊ตฌ ๋ฐ ํ˜•์‹ ๋ถ„์„ ์ž‘์—…์— ์‚ฌ์šฉ๋˜๋Š” ์—ฐ๊ตฌ ํ”Œ๋žซํผ์ž…๋‹ˆ๋‹ค. ๊ฒ€์ƒ‰ ์ฝ˜์†” ๋ฐ์ดํ„ฐ์—์„œ "jelly static analyzer javascript async support paper" ๋ฐ "TAJS async await support"์™€ ๊ฐ™์€ ๊ฒ€์ƒ‰์–ด๋Š” ๊ฐœ๋ฐœ์ž๋“ค์ด ์ผ์ƒ์ ์ธ ๊ฐœ๋ฐœ ๋„๊ตฌ๋ฅผ ์ฐพ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ด๋Ÿฌํ•œ ํ•™์ˆ ์ ์ธ ๋„๊ตฌ๋ฅผ ์—ฐ๊ตฌํ•˜๊ฑฐ๋‚˜ ์ธ์šฉํ•˜๋Š” ๊ฒƒ์„ ๋ฐ˜์˜ํ•ฉ๋‹ˆ๋‹ค.

SonarQube์˜ javascript:S4328 ๊ด€๋ จ ๋น„๋™๊ธฐ ๊ทœ์น™์€ ํ”„๋กœ๋•์…˜ ํ’ˆ์งˆ ๋ถ„์„์—์„œ ํ”ํžˆ ๋ฐœ์ƒํ•˜๋Š” ๋ช‡ ๊ฐ€์ง€ ๋น„๋™๊ธฐ ์•ˆํ‹ฐ ํŒจํ„ด์„ ๊ฐ์ง€ํ•ฉ๋‹ˆ๋‹ค.

์‹ค์ œ ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ ์‚ฌ์šฉํ•˜๋ ค๋ฉด TypeScript์˜ ํƒ€์ž… ๊ฒ€์‚ฌ๊ธฐ์™€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. typescript-eslintSonarQube์˜ ๋น„๋™๊ธฐ ์ธ์‹ ๊ทœ์น™๊ณผ ํ’ˆ์งˆ ๊ฒŒ์ดํŠธ๋Š” ์˜ค๋Š˜๋‚  ํ‘œ์ค€ ๋„๊ตฌ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ€์žฅ ์ฒ ์ €ํ•œ ๋น„๋™๊ธฐ ์•ˆ์ „์„ฑ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

Snyk Code: ๊ฐœ๋ฐœ์ž ์šฐ์„  ๋ณด์•ˆ ์Šค์บ”

Snyk Code๋Š” ๊ฐœ๋ฐœ์ž ๊ฒฝํ—˜์— ์ค‘์ ์„ ๋‘” SAST ์Šค์บ๋‹ ์†”๋ฃจ์…˜์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. VS Code ๋ฐ JetBrains IDE์— ํ†ตํ•ฉ๋˜์–ด ๊ฐœ๋ฐœ์ž๊ฐ€ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋™์•ˆ ๋ฐœ๊ฒฌ ์‚ฌํ•ญ์„ ๋ฐ”๋กœ ํ‘œ์‹œํ•˜๊ณ , ๊ฐ ๋ฐœ๊ฒฌ ์‚ฌํ•ญ์— ๋Œ€ํ•œ ํ•ด๊ฒฐ ์˜ˆ์‹œ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ž์ฒด ๊ฐœ๋ฐœํ•œ ๋จธ์‹ ๋Ÿฌ๋‹ ๊ธฐ๋ฐ˜ ๋ถ„์„ ์—”์ง„์„ ์‚ฌ์šฉํ•˜์—ฌ JavaScript ๋ฐ TypeScript ์ฝ”๋“œ๋ฒ ์ด์Šค ์ „๋ฐ˜์— ๊ฑธ์ณ ์˜ค์—ผ ์ถ”์ ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

์„ธ๊ฒŒ ๋•Œ๋ฆฌ๋‹ค

# Install Snyk CLI
npm install --save-dev snyk

# Authenticate and scan
npx snyk auth
npx snyk code test

Snyk Code๋Š” IDE๋ฅผ ๋ฒ—์–ด๋‚˜์ง€ ์•Š๊ณ  ๋ณด์•ˆ ํ”ผ๋“œ๋ฐฑ์„ ๋ฐ›๊ณ ์ž ํ•˜๋Š” ํŒ€์—๊ฒŒ ํŠนํžˆ ํšจ๊ณผ์ ์ž…๋‹ˆ๋‹ค. Snyk Code์˜ ์ˆ˜์ • ์ œ์•ˆ์€ CodeQL์˜ ์ฟผ๋ฆฌ ์ค‘์‹ฌ ์ถœ๋ ฅ๋ณด๋‹ค ๊ฐœ๋ฐœ์ž ์นœํ™”์ ์ด๋ฏ€๋กœ ์ทจ์•ฝ์  ํƒ์ง€์™€ ํ•จ๊ป˜ ๋ณด์•ˆ ๊ต์œก์— ๋” ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

๊ณ„์ธตํ˜• JavaScript ์ •์  ๋ถ„์„ ์Šคํƒ ๊ตฌ์ถ•

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ •์  ๋ถ„์„์— ๋Œ€ํ•œ ์˜ฌ๋ฐ”๋ฅธ ์ ‘๊ทผ ๋ฐฉ์‹์€ ํ•˜๋‚˜์˜ ๋„๊ตฌ๋ฅผ ์„ ํƒํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ์ค‘๋ณต์ด ํฌ์ง€ ์•Š์œผ๋ฉด์„œ ์„œ๋กœ ๋‹ค๋ฅธ ๊ณ„์ธต์„ ๋‹ค๋ฃจ๋Š” ๋„๊ตฌ๋“ค์„ ์กฐํ•ฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ธต์ˆ˜๋‹จ๊ทธ๊ฒƒ์ด ์‹คํ–‰๋  ๋•Œ
์„œ์‹์ƒํƒœ๊ณ„ ๋˜๋Š” ๋” ์•„๋ฆ„๋‹ค์šด์‚ฌ์ „ ์ปค๋ฐ‹(๋น ๋ฅธ)
๋ณดํ’€ESLint + typescript-eslint์‚ฌ์ „ ์ปค๋ฐ‹ + CI
์œ ํ˜• ํ™•์ธtsc --noEmitCI
๋ณด์•ˆ ์Šค์บ๋‹Semgrep ๋˜๋Š” Snyk ์ฝ”๋“œCI (๋ชจ๋“  PR)
์‹ฌ์ธต ์ทจ์•ฝ์  ์Šค์บ๋‹CodeQLCI (์˜ˆ์ • ๋˜๋Š” PR)
์ฃฝ์€ ์ฝ”๋“œ ๊ฐ์ง€์ž๋ฅด๋‹คCI (์ฃผ๊ฐ„ ๋˜๋Š” ์›”๊ฐ„)
ํ’ˆ์งˆ ๊ด€๋ฆฌ ๊ฒŒ์ดํŠธ + ์ถ”์„ธ ์ถ”์ ์†Œ๋‚˜ํ๋ธŒCI (๋ชจ๋“  PR)
์ข…์†์„ฑ ์ทจ์•ฝ์  ์Šค์บ”npm audit + ์Šค๋‹‰CI(๋ชจ๋“  ๋นŒ๋“œ)

ํŒ€์ด ์•„๋ฌด๊ฒƒ๋„ ์—†๋Š” ์ƒํƒœ์—์„œ ์‹œ์ž‘ํ•  ๋•Œ ํ•„์š”ํ•œ ์ตœ์†Œํ•œ์˜ ์Šคํƒ: ESLint + typescript-eslint + npm audit๋ณด์•ˆ ์š”๊ตฌ ์‚ฌํ•ญ์ด ์ฆ๊ฐ€ํ•˜๋ฉด Semgrep ๋˜๋Š” Snyk Code๋ฅผ ์ถ”๊ฐ€ํ•˜์‹ญ์‹œ์˜ค. ํŒ€์—์„œ ํ’ˆ์งˆ ์ถ”์„ธ ๊ฐ€์‹œ์„ฑ ๋ฐ ๊ด€๋ฆฌ ๋ณด๊ณ ๊ฐ€ ํ•„์š”ํ•˜๋ฉด SonarQube๋ฅผ ์ถ”๊ฐ€ํ•˜์‹ญ์‹œ์˜ค.

์–Œ

# .github/workflows/quality.yml
name: JavaScript Code Quality
on: [push, pull_request]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: "20" }
      - run: npm ci
      - run: npx tsc --noEmit
      - run: npx eslint src/ --max-warnings 0

  security:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: "20" }
      - run: npm ci
      - run: npm audit --audit-level=high
      - run: npx semgrep scan --config=p/javascript --error src/

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๋Œ€๊ทœ๋ชจ ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ ์‹œ์Šคํ…œ์—์„œ ์‚ฌ์šฉ๋  ๋•Œ

๊ธฐ์—… ํ™˜๊ฒฝ์—์„œ JavaScript ๋ฐ TypeScript ์„œ๋น„์Šค๋Š” COBOL ํ”„๋กœ๊ทธ๋žจ, Java ๋ฐฑ์—”๋“œ, Python ๋ฐ์ดํ„ฐ ํŒŒ์ดํ”„๋ผ์ธ, ๊ทธ๋ฆฌ๊ณ  ๊ธฐ์กด ๋ฉ”์ธํ”„๋ ˆ์ž„ ์‹œ์Šคํ…œ๊ณผ ์ ์  ๋” ๊ณต์กดํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋งฅ๋ฝ์—์„œ ์œ„์˜ ์ •์  ๋ถ„์„ ๋„๊ตฌ๋“ค์€ JavaScript ๊ฒฝ๊ณ„ ๋‚ด์—์„œ๋Š” ์ฒ ์ €ํ•œ ๊ฐ€์‹œ์„ฑ์„ ์ œ๊ณตํ•˜์ง€๋งŒ, ๊ทธ ๊ฒฝ๊ณ„๋ฅผ ๋„˜์–ด์„œ๋Š” ์—ฐ๊ฒฐ์— ๋Œ€ํ•ด์„œ๋Š” ์ „ํ˜€ ํŒŒ์•…ํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค.

COBOL ๋ฐฐ์น˜ ์ž‘์—…์œผ๋กœ ์ฑ„์›Œ์ง„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๋Š” Node.js ์„œ๋น„์Šค๋Š” ์–ด๋–ค JavaScript ๋ถ„์„ ๋„๊ตฌ๋„ ํŒŒ์•…ํ•  ์ˆ˜ ์—†๋Š” ๋ฐฉ์‹์œผ๋กœ ํ•ด๋‹น COBOL ํ”„๋กœ๊ทธ๋žจ์— ์˜์กดํ•ฉ๋‹ˆ๋‹ค. COBOL ํ”„๋กœ๊ทธ๋žจ์„ ํ˜ธ์ถœํ•˜๋Š” Java API๋ฅผ ํ˜ธ์ถœํ•˜๋Š” React ํ”„๋ŸฐํŠธ์—”๋“œ๋Š” ์„ธ ๊ฐ€์ง€ ์–ธ์–ด ๊ฒฝ๊ณ„๋ฅผ ๋„˜๋‚˜๋“œ๋Š” ์˜์กด์„ฑ ์ฒด์ธ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”๋ฐ, ์ด ์ฒด์ธ์€ ์–ด๋–ค ๋‹จ์ผ ์–ธ์–ด ๋ถ„์„ ๋„๊ตฌ์˜ ๊ด€์ ์—์„œ๋„ ๋ณด์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

SMART TS XL ์ด ์†”๋ฃจ์…˜์€ ์ „์ฒด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํฌํŠธํด๋ฆฌ์˜ค์— ๊ฑธ์ณ ์–ธ์–ด ๊ฐ„ ์˜์กด์„ฑ ๋ถ„์„์„ ์ œ๊ณตํ•จ์œผ๋กœ์จ ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค. JavaScript ๋ชจ๋“ˆ์ด ๊ณต์œ  ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ์— ์–ด๋–ป๊ฒŒ ์˜์กดํ•˜๋Š”์ง€, API ๊ณ„์•ฝ์ด ํ”„๋ŸฐํŠธ์—”๋“œ์™€ ๋ฐฑ์—”๋“œ ์„œ๋น„์Šค๋ฅผ ์–ด๋–ป๊ฒŒ ์—ฐ๊ฒฐํ•˜๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  ์‹œ์Šคํ…œ์˜ ํ•œ ๋ถ€๋ถ„์—์„œ ๋ฐœ์ƒํ•œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ๋‹ค๋ฅธ ์–ธ์–ด์˜ ๊ตฌ์„ฑ ์š”์†Œ์— ์–ด๋–ป๊ฒŒ ์ „ํŒŒ๋˜๋Š”์ง€๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ํ†ตํ•ฉ ๋ชจ๋ธ์„ ๊ตฌ์ถ•ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๋ฐ”๋กœ ๊ทธ ์†”๋ฃจ์…˜์ž…๋‹ˆ๋‹ค. ๋‹ค๊ตญ์–ด ์•„ํ‚คํ…์ฒ˜ ๋ถ„์„ ์ด๋Š” ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ ์•„ํ‚คํ…์ฒ˜ ํŒ€์ด ์—ฌ๋Ÿฌ ์–ธ์–ด์™€ ํ”Œ๋žซํผ์— ๊ฑธ์ณ ์žˆ๋Š” ์‹œ์Šคํ…œ ๋ณ€๊ฒฝ์„ ๊ณ„ํšํ•  ๋•Œ ํ•„์š”ํ•œ ๊ธฐ๋Šฅ์ด๋ฉฐ, ์ด ๊ฐ€์ด๋“œ์—์„œ ๋‹ค๋ฃจ๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ด€๋ จ ๋„๊ตฌ์™€ ๊ฒฝ์Ÿํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋ณด์™„ํ•˜๋Š” ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋งฅ๋ฝ์—์„œ ์„ค๋ช…ํ•˜์ž๋ฉด, ์˜์กด์„ฑ ๊ทธ๋ž˜ํ”„ ๋ฐ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์œ„ํ—˜๋ณ€๊ฒฝ์„ ํ•˜๊ธฐ ์ „์— ์‹œ์Šคํ…œ์˜ ์ „์ฒด ์˜์กด์„ฑ ๊ตฌ์กฐ๋ฅผ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์ด ์•ˆ์ „ํ•œ ๋ฆฌํŒฉํ† ๋ง๊ณผ ์•„๋ฌด๋„ ํ…Œ์ŠคํŠธํ•  ์ƒ๊ฐ์„ ํ•˜์ง€ ๋ชปํ•œ ๊ตฌ์„ฑ ์š”์†Œ์—์„œ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋Š” ๋ณ€๊ฒฝ์„ ๊ตฌ๋ถ„ํ•˜๋Š” ๊ธฐ์ค€์ž…๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๋Œ€๊ทœ๋ชจ ํ™˜๊ฒฝ ๋‚ด์—์„œ JavaScript์— ํŠนํ™”๋œ ๋ถ„์„์„ ์ˆ˜ํ–‰ํ•˜๋ ค๋ฉด, SMART TS XL์˜ ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ ์ฝ”๋“œ ์ธํ…”๋ฆฌ์ „์Šค ์ด ์†”๋ฃจ์…˜์€ COBOL, JCL, Java, Python ๋ฐ ๊ธฐํƒ€ ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ ์–ธ์–ด๋Š” ๋ฌผ๋ก  JavaScript ๋ฐ TypeScript๋ฅผ ์ง€์›ํ•˜๋ฉฐ, ๋‹จ์ผ ํ”Œ๋žซํผ์—์„œ ํ†ตํ•ฉ๋œ ํ’ˆ์งˆ ์ง€ํ‘œ์™€ ์ข…์†์„ฑ ๊ฐ€์‹œ์„ฑ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์ƒํ™ฉ์— ๋งž๋Š” ์ ์ ˆํ•œ ๋„๊ตฌ ์„ ํƒํ•˜๊ธฐ

๋‹จ์ผ ๋„๊ตฌ๋กœ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ •์  ๋ถ„์„์˜ ๋ชจ๋“  ์ธก๋ฉด์„ ๋‹ค๋ฃฐ ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์–ด๋–ค ๋„๊ตฌ๋ฅผ ์„ ํƒํ• ์ง€๋Š” ํŒ€ ๊ทœ๋ชจ, ๋ณด์•ˆ ์š”๊ตฌ ์‚ฌํ•ญ, ๊ธฐ์กด ๋„๊ตฌ ๋ชจ์Œ, ๊ทธ๋ฆฌ๊ณ  ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋…๋ฆฝ์ ์œผ๋กœ ์ž‘๋™ํ•˜๋Š”์ง€ ์•„๋‹ˆ๋ฉด ๋” ํฐ ๋‹ค๊ตญ์–ด ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ ์‹œ์Šคํ…œ์˜ ์ผ๋ถ€๋กœ ์ž‘๋™ํ•˜๋Š”์ง€์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง‘๋‹ˆ๋‹ค.

์ƒˆ๋กœ์šด ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋Š” 1์ธ ๊ฐœ๋ฐœ์ž ๋˜๋Š” ์†Œ๊ทœ๋ชจ ํŒ€์˜ ๊ฒฝ์šฐ: Biome(๋ฆฐํŒ… ๋ฐ ํฌ๋งทํŒ…)๊ณผ TypeScript ์—„๊ฒฉ ๋ชจ๋“œ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜์„ธ์š”. npm audit ์ข…์†์„ฑ ๋ณด์•ˆ์„ ์œ„ํ•ด์„œ์ž…๋‹ˆ๋‹ค.

์ค‘๊ทœ๋ชจ ํŒ€์ด ์‹ค์ œ ์šด์˜ ํ™˜๊ฒฝ์— ๋งž๋Š” ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœํ•  ๊ฒฝ์šฐ, ESLint(typescript-eslint ํฌํ•จ), Prettier, TypeScript ์—„๊ฒฉ ๋ชจ๋“œ, CI ํ™˜๊ฒฝ์—์„œ์˜ ๋ณด์•ˆ ๊ฐ•ํ™”๋ฅผ ์œ„ํ•œ Semgrep, ๊ทธ๋ฆฌ๊ณ  ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ์ฝ”๋“œ ํƒ์ง€๋ฅผ ์œ„ํ•œ Knip์„ ์ถ”์ฒœํ•ฉ๋‹ˆ๋‹ค.

๊ทœ์ • ์ค€์ˆ˜ ๋ฐ ๋ณด์•ˆ ์š”๊ตฌ ์‚ฌํ•ญ์ด ์žˆ๋Š” ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ ํŒ€์˜ ๊ฒฝ์šฐ: ํ’ˆ์งˆ ๊ฒŒ์ดํŠธ ๋ฐ ์ถ”์„ธ ์ถ”์ ์„ ์œ„ํ•œ SonarQube, ์‹ฌ์ธต ์ทจ์•ฝ์  ์Šค์บ”์„ ์œ„ํ•œ CodeQL, ๊ฐœ๋ฐœ์ž ๋Œ€์ƒ ๋ณด์•ˆ ํ”ผ๋“œ๋ฐฑ์„ ์œ„ํ•œ Snyk Code, SMART TS XL ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋ ˆ๊ฑฐ์‹œ ์‹œ์Šคํ…œ์ด๋‚˜ ๋‹ค๊ตญ์–ด ์‹œ์Šคํ…œ๊ณผ ์ƒํ˜ธ ์ž‘์šฉํ•˜๋Š” ๊ฒฝ์šฐ.

๋ชจ๋…ธ๋ ˆํฌ ํ™˜๊ฒฝ์—์„œ ์„ฑ๋Šฅ ๋•Œ๋ฌธ์— ESLint ๋Œ€์•ˆ์„ ํ‰๊ฐ€ํ•˜๋Š” ํŒ€์ด๋ผ๋ฉด, ์†๋„์— ์ค‘์ ์„ ๋‘” OxcLint ๋˜๋Š” ๋ฆฐํ„ฐ์™€ ํฌ๋งทํ„ฐ๋ฅผ ์™„๋ฒฝํ•˜๊ฒŒ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ๋Š” Biome์„ ๊ณ ๋ คํ•ด ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.