์ •์  ์ฝ”๋“œ ๋ถ„์„์—์„œ์˜ ์˜คํƒ

์ •์  ์ฝ”๋“œ ๋ถ„์„์—์„œ ์˜คํƒ์„ ์ค„์ด๋Š” ๋ฐฉ๋ฒ•

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

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

์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ์ฝ”๋“œ์—์„œ ๋ฐœ๊ฒฌ๋œ ๋‚ด์šฉ์— ๋Œ€ํ•œ ์กฐ์‚ฌ ์ž‘์—…์„ ์ค‘๋‹จํ•˜์„ธ์š”.

SMART TS XL ํŒ€์ด ์‹œ๊ฐ„์„ ๋‚ญ๋น„ํ•˜๊ธฐ ์ „์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋Š” ์ฝ”๋“œ์— ์–ด๋–ค ํ”Œ๋ž˜๊ทธ๋œ ํŒจํ„ด์ด ์žˆ๋Š”์ง€ ์‹๋ณ„ํ•ฉ๋‹ˆ๋‹ค.

๋” ๋งŽ์€ ์ •๋ณด

์ฐจ๋ก€

์ •์  ์ฝ”๋“œ ๋ถ„์„์—์„œ ์˜คํƒ(False Positive)์ด๋ž€ ๋ฌด์—‡์ธ๊ฐ€์š”?

์˜คํƒ(false positive)์€ ์ •์  ๋ถ„์„ ๋„๊ตฌ๊ฐ€ ์‹ค์ œ๋กœ๋Š” ์˜ฌ๋ฐ”๋ฅธ ์ฝ”๋“œ๋ฅผ ๋ฌธ์ œ ์žˆ๋Š” ์ฝ”๋“œ๋กœ ์ž˜๋ชป ํ‘œ์‹œํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ ๋งํ•ฉ๋‹ˆ๋‹ค. ํ‘œ์‹œ๋œ ์ฝ”๋“œ๋Š” ๋Ÿฐํƒ€์ž„ ์‹œ ๋ฒ„๊ทธ, ์ทจ์•ฝ์  ๋˜๋Š” ํ’ˆ์งˆ ์œ„๋ฐ˜์„ ๋ฐœ์ƒ์‹œํ‚ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋„๊ตฌ์˜ ๋ถ„์„ ๊ฒฐ๊ณผ๊ฐ€ ํ”„๋กœ๊ทธ๋žจ์˜ ์‹ค์ œ ๋™์ž‘๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ „์ฒด ๋ถ„๋ฅ˜ ์ฒด๊ณ„๋ฅผ ์ดํ•ดํ•˜๋ฉด ๋ฌด์—‡์„ ๋จผ์ € ์ˆ˜์ •ํ•ด์•ผ ํ• ์ง€ ์šฐ์„ ์ˆœ์œ„๋ฅผ ์ •ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

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

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

์ •์  ๋ถ„์„์—์„œ ์˜คํƒ์ด ๋ฐœ์ƒํ•˜๋Š” ์ด์œ : ๊ธฐ์ˆ ์  ์›์ธ

๊ฐ ์˜คํƒ ์œ ํ˜•์˜ ๋ฐœ์ƒ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์ดํ•ดํ•˜๋ฉด ์˜ฌ๋ฐ”๋ฅธ ํ•ด๊ฒฐ์ฑ…์„ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

1. ๋งฅ๋ฝ ์—†๋Š” ์ ˆ์ฐจ ๋‚ด ๋ถ„์„

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

c

// Caller always validates before calling -- analyzer doesn't know this
void process(Data *d) {
    int result = d->value;  // flagged: potential null dereference
    // But every caller looks like:
    // if (d != NULL) process(d);
}

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•: ์ ˆ์ฐจ ๊ฐ„ ๋ถ„์„์œผ๋กœ ์ „ํ™˜ํ•˜๊ฑฐ๋‚˜, ์ฃผ์„์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ถ„์„๊ธฐ์— ์‚ฌ์ „ ์กฐ๊ฑด์„ ์•Œ๋ ค์ฃผ์„ธ์š”.

2. ๊ฐ’ ๋ฒ”์œ„์˜ ๊ณผ๋Œ€ ์ถ”์ •

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

์ž๋ฐ”

// Analyzer computes divisor range as [0, 100] and flags division by zero
// Actual runtime: config.getMinBatchSize() always returns >= 1
int batchCount = totalItems / config.getMinBatchSize();  // flagged

๊ณ ์น˜๋‹ค: ๋ถ„์„๊ธฐ๊ฐ€ ์ถ”์ ํ•˜๋Š” ๋ฒ”์œ„๋ฅผ ์ขํžˆ๋Š” ์–ด์„ค์…˜ ๋˜๋Š” ์‚ฌ์ „ ์กฐ๊ฑด์„ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜, ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ถ„์„๊ธฐ๋ฅผ ๊ตฌ์„ฑํ•˜์‹ญ์‹œ์˜ค. getMinBatchSize().

3. ํƒ€์‚ฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์˜ค๊ฒฝ๋ณด

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

4. ์˜๋ฏธ๋ก ์  ์ดํ•ด ์—†์ด ์ ์šฉ๋˜๋Š” ํŒจํ„ด ๊ทœ์น™

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

5. ์ •์ ์œผ๋กœ ํ‰๊ฐ€๋œ ์กฐ๊ฑด

์ด๋Š” SC ์ฟผ๋ฆฌ "์กฐ๊ฑด์ด ์ •์ ์œผ๋กœ ๊ฑฐ์ง“์œผ๋กœ ํ‰๊ฐ€๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ฝ”๋“œ๊ฐ€ ๋ถ„์„๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค"์˜ ๊ทผ๋ณธ์ ์ธ ์›์ธ์ž…๋‹ˆ๋‹ค. Coverity/Clang ๋ถ„์„๊ธฐ์—์„œ ํ”ํžˆ ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ๊ณ ์ด๋ฏ€๋กœ ๋ณ„๋„์˜ ์„น์…˜์—์„œ ์ž์„ธํžˆ ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

"์กฐ๊ฑด์ด ์ •์ ์œผ๋กœ ๊ฑฐ์ง“์œผ๋กœ ํ‰๊ฐ€๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ฝ”๋“œ๊ฐ€ ๋ถ„์„๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."

์ด ๊ฒฝ๊ณ ๋Š” Coverity, Clang Static Analyzer ๋ฐ ์œ ์‚ฌํ•œ ๋„๊ตฌ์—์„œ ๋ถ„์„๊ธฐ๊ฐ€ ๋ถ„๊ธฐ ์กฐ๊ฑด์ด ํ•ญ์ƒ ๊ฑฐ์ง“์ด๋ผ๊ณ  ํŒ๋‹จํ•  ๋•Œ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค. ์ฆ‰, ํ•ด๋‹น ๋ถ„๊ธฐ ๋‚ด์˜ ์ฝ”๋“œ๋Š” ์–ด๋–ค ์‹คํ–‰์—์„œ๋„ ๋„๋‹ฌํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ ๋ถ„์„๊ธฐ๊ฐ€ ํ•ด๋‹น ๋ถ„๊ธฐ ๋‚ด๋ถ€ ๋ถ„์„์„ ์ค‘๋‹จํ•œ๋‹ค๋Š” ์˜๋ฏธ์ž…๋‹ˆ๋‹ค.

๋ฐœ์ƒ ์›์ธ:

c

#define DEBUG 0  // compile-time constant

void process_record(Record *r) {
    if (DEBUG) {
        validate_record(r);  // never analyzed -- condition always false
    }
    use_record(r);  // potential issue here not caught if validate_record was needed
}

๋ถ„์„๊ธฐ๋Š” ํ‰๊ฐ€ํ•ฉ๋‹ˆ๋‹ค if (DEBUG) as if (0)์ด ๊ฒฝ๊ณ ๋Š” ํ•ญ์ƒ ๊ฑฐ์ง“์ด๋ฉฐ ๋ณธ๋ฌธ์„ ๋ถ„์„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์˜ฌ๋ฐ”๋ฅธ ๋™์ž‘์ž…๋‹ˆ๋‹ค. ์ฝ”๋“œ๋Š” ์‹ค์ œ๋กœ ๋„๋‹ฌํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝ๊ณ ๋Š” ์ •๋ณด ์ œ๊ณต์šฉ์ด๋ฉฐ ๋ฒ„๊ทธ์— ๋Œ€ํ•œ ์˜คํƒ์ด ์•„๋‹™๋‹ˆ๋‹ค.

๋ฌธ์ œ๊ฐ€ ๋˜๋Š” ์‹œ์ :

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

์ผ๋ฐ˜์ ์ธ ์›์ธ:

c

// Pattern 1: debug-only guard on production-required code
if (ENABLE_VALIDATION) { validate_input(data); }  // if ENABLE_VALIDATION=0, no validation

// Pattern 2: error return always overwritten before checked
int result = do_operation();
result = 0;  // overwrites result -- subsequent if (result != 0) is always false
if (result != 0) { handle_error(); }  // never reached

// Pattern 3: overly conservative NULL check after guaranteed assignment
ptr = malloc(sizeof(Data));
if (ptr == NULL) { ... }  // valid -- malloc can return NULL
ptr->value = 0;
if (ptr == NULL) { ... }  // always false -- analyzer warns here correctly

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•: ํ•ด๋‹น ๋ถ„๊ธฐ์— ๋„๋‹ฌํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ์กฐ๊ฑด์„ ์ˆ˜์ •ํ•˜์‹ญ์‹œ์˜ค. ์˜๋„์ ์œผ๋กœ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ์ฝ”๋“œ์ด๋ฏ€๋กœ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ๋Š” ์ฝ”๋“œ๋ผ๋ฉด ์ œ๊ฑฐํ•˜์‹ญ์‹œ์˜ค. ๋””๋ฒ„๊ทธ ์ „์šฉ ์ฝ”๋“œ์ด๊ณ  ์กฐ๊ฑด๋ฌธ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ž‘์„ฑ๋œ ๊ฒฝ์šฐ, ๊ฒฝ๊ณ ๋Š” ์˜ˆ์ƒ๋˜๋Š” ๊ฒƒ์ด๋ฏ€๋กœ ํ‘œ์‹œํ•˜์ง€ ์•Š์•„๋„ ๋ฉ๋‹ˆ๋‹ค.

๋‹ค์–‘ํ•œ ๋„๊ตฌ์— ๊ฑธ์นœ ์–ต์ œ ๋ฉ”์ปค๋‹ˆ์ฆ˜

์–ต์ œ(Suppression)๋Š” ํŠน์ • ์œ„์น˜์—์„œ ํŠน์ • ๊ฒฐ๊ณผ๋ฅผ ๋ฌด์‹œํ•˜๋„๋ก ๋„๊ตฌ์— ์ง€์‹œํ•ฉ๋‹ˆ๋‹ค. ์ฃผ์š” ์ •์  ๋ถ„์„ ๋„๊ตฌ๋Š” ๋ชจ๋‘ ์–ต์ œ ๊ตฌ๋ฌธ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๊ทœ์น™ ์กฐ์ •์ด ํ˜„์‹ค์ ์œผ๋กœ ์–ด๋ ค์šด, ํ™•์ธ๋œ ์˜คํƒ์— ๋Œ€ํ•ด ์–ต์ œ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜์‹ญ์‹œ์˜ค.

๊ฒฝ๊ณ : ์ฐจ๋‹จ ๊ธฐ๋ก์€ ์ฃผ๊ธฐ์ ์œผ๋กœ ๊ฒ€ํ† ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. 2023๋…„์— ์˜คํƒ์œผ๋กœ ์ธํ•ด ์ถ”๊ฐ€๋œ ์ฐจ๋‹จ ์กฐ์น˜๊ฐ€ 2025๋…„์— ๋™์ผํ•œ ์œ„์น˜์— ๋„์ž…๋œ ์‹ค์ œ ์ทจ์•ฝ์ ์„ ์ฐจ๋‹จํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

ESLint(์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ/ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ)

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

// Suppress next line
// eslint-disable-next-line no-unused-vars
const legacyAdapter = require('./legacy');

// Suppress a block
/* eslint-disable @typescript-eslint/no-explicit-any */
function processLegacyData(data: any): void { ... }
/* eslint-enable @typescript-eslint/no-explicit-any */

์†Œ๋‚˜ํ๋ธŒ / ์†Œ๋‚˜๋ฆฐํŠธ

์ž๋ฐ”

@SuppressWarnings("java:S2077")  // Suppress SQL injection rule for this method
public List<User> searchUsers(String query) {
    // This method uses a parameterized query builder, not raw string concat
    return queryBuilder.executeParameterized(query);
}

๋˜๋Š” SonarQube์—์„œ ์ธ๋ผ์ธ ์ฃผ์„์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•:

์ž๋ฐ”

String hash = md5(password);  // NOSONAR - md5 used for non-security cache key only

Pylint(ํŒŒ์ด์ฌ)

ํŒŒ์ด์ฌ

import os  # pylint: disable=unused-import  -- required for side-effect registration

def legacy_function():
    pass  # pylint: disable=W0107  -- intentionally empty for interface compliance

์…ˆ๊ทธ๋ ™

์–Œ

# .semgrepignore -- exclude paths
tests/fixtures/
vendor/

# Inline: suppress specific rule at a line
result = eval(expression)  # nosemgrep: python.lang.security.audit.eval-injection

์ปค๋ฒ„๋ฆฌํ‹ฐ

c

/* coverity[null_returns] */
Data *ptr = get_config();  // Coverity: ptr may be NULL
// Function contract guarantees non-NULL return when config is initialized

์ฒด๊ณ„์ ์ธ ์˜คํƒ์„ ์ค„์ด๊ธฐ ์œ„ํ•œ ์กฐ์ • ๊ทœ์น™

์–ต์ œ๋Š” ๊ฐœ๋ณ„ ์‚ฌ๋ก€๋ฅผ ๋‹ค๋ฃน๋‹ˆ๋‹ค. ๊ทœ์น™ ์กฐ์ •์€ ๊ทœ์น™์ด ์ •์ƒ์ ์ธ ์ฝ”๋“œ์— ๋Œ€ํ•ด ์ง€์†์ ์œผ๋กœ ์˜คํƒ์„ ์ƒ์„ฑํ•˜๋Š” ์ฒด๊ณ„์ ์ธ ํŒจํ„ด์„ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

์–Œ

# SonarQube quality profile configuration
# Reduce sensitivity for cognitive complexity rule
sonar.java.cognitive.complexity.threshold=20  # default 15; raises bar for flagging

# Exclude generated code from analysis
sonar.exclusions=**/generated/**,**/proto/**,**/target/**
sonar.coverage.exclusions=**/*Test.java,**/*Spec.java

# Configure security hotspot categories by risk
# In sonar-project.properties:
sonar.security.hotspot.threshold=HIGH  # only show HIGH severity hotspots

์–Œ

# ESLint: rule-level tuning
# .eslintrc or eslint.config.js
rules:
  "@typescript-eslint/no-explicit-any": "warn"   # was "error" -- downgrade for gradual migration
  "complexity": ["warn", { "max": 20 }]           # was 10 -- adjust for legacy codebase baseline
  "max-lines-per-function": ["warn", { "max": 60, "skipBlankLines": true }]

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

CI/CD ํŒŒ์ดํ”„๋ผ์ธ์˜ ์˜คํƒ์ง€

๋ถ„์„ ๊ฒฐ๊ณผ์— ๋”ฐ๋ผ ๋ณ‘ํ•ฉ์„ ์ฐจ๋‹จํ•˜๋Š” CI/CD ํŒŒ์ดํ”„๋ผ์ธ์—์„œ ์˜คํƒ์€ ๊ฐœ๋ฐœ ์†๋„์— ์ง์ ‘์ ์ธ ์˜ํ–ฅ์„ ๋ฏธ์นฉ๋‹ˆ๋‹ค. ๋ณ‘ํ•ฉํ•  ๋•Œ๋งˆ๋‹ค ์˜คํƒ 3๊ฐœ๋กœ ์ธํ•ด ํ’€ ๋ฆฌํ€˜์ŠคํŠธ๊ฐ€ ์ฐจ๋‹จ๋˜๋ฉด ๊ฐœ๋ฐœ์ž๋Š” ํ•ด๋‹น ์ฐจ๋‹จ ๊ธฐ๋Šฅ์„ ์‹ ๋ขฐํ•˜๊ธฐ๋ณด๋‹ค๋Š” ์šฐํšŒํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ฐพ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

ํŒŒ์ดํ”„๋ผ์ธ๋ณ„ ์˜คํƒ ๊ด€๋ฆฌ ์ „๋žต:

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

์–Œ

# .github/workflows/analysis.yml
- name: SonarCloud Scan
  uses: SonarSource/sonarcloud-github-action@master
  with:
    args: >
      -Dsonar.pullrequest.base=${{ github.base_ref }}
      -Dsonar.pullrequest.branch=${{ github.head_ref }}
      # New-code analysis only: existing findings don't block

์‹ฌ๊ฐ๋„ ์ž„๊ณ„๊ฐ’์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์‹ฌ๊ฐ๋„๊ฐ€ '์‹ฌ๊ฐ' ๋ฐ '๋†’์Œ'์ธ ๊ฒฝ์šฐ์—๋งŒ ํŒŒ์ดํ”„๋ผ์ธ์„ ์‹คํŒจ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. '์ค‘๊ฐ„' ๋ฐ '๋‚ฎ์Œ'์ธ ๊ฒฝ์šฐ๋Š” ์ฐจ๋‹จํ•˜์ง€ ์•Š๊ณ  ๊ฒฝ๊ณ ๋กœ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ์ค€ ํŒŒ์ผ. Semgrep ๋ฐ Grype์™€ ๊ฐ™์€ ๋„๊ตฌ๋Š” ํŠน์ • ์ปค๋ฐ‹ ์‹œ์ ์— ์กด์žฌํ•˜๋Š” ๋ฐœ๊ฒฌ ์‚ฌํ•ญ์„ ๊ธฐ๋กํ•˜๋Š” ๊ธฐ์ค€ ํŒŒ์ผ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ์ƒˆ ์‹คํ–‰ ์‹œ์—๋Š” ๊ธฐ์ค€ ํŒŒ์ผ ์ดํ›„์— ๋ฐœ์ƒํ•œ ๋ฐœ๊ฒฌ ์‚ฌํ•ญ๋งŒ ๋ณด๊ณ ๋˜๋ฉฐ, ๊ธฐ์กด์˜ ์˜คํƒ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ๊ฐœ๋ณ„ ์ธ์Šคํ„ด์Šค ์–ต์ œ ์—†์ด ์–ต์ œ๋ฉ๋‹ˆ๋‹ค.

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

# Semgrep: establish baseline, then compare
semgrep scan --baseline-commit=main --output=results.sarif src/
# Only findings introduced since main are reported

์˜คํƒ๋ฅ  ์ธก์ • ๋ฐ ์ถ”์ 

์ธก์ • ์—†์ด ์˜คํƒ์„ ์ค„์ด๋Š” ๊ฒƒ์€ ์ถ”์ธก์— ๋ถˆ๊ณผํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ ์ง€ํ‘œ๋“ค์„ ์‹œ๊ฐ„์— ๋”ฐ๋ผ ์ถ”์ ํ•˜์„ธ์š”.

๋ฉ”ํŠธ๋ฆญ๊ณ„์‚ฐ ๋ฐฉ๋ฒ•๋ชฉํ‘œ
์˜คํƒ์œจํ™•์ง„๋œ ์œ„์–‘์„ฑ ์‚ฌ๋ก€ ์ˆ˜ / ์ „์ฒด ์ง„๋‹จ ๊ฑด์ˆ˜ ร— 100%๋ณด์•ˆ ๋„๊ตฌ์˜ ๊ฒฝ์šฐ 20% ๋ฏธ๋งŒ, ํ’ˆ์งˆ ๋„๊ตฌ์˜ ๊ฒฝ์šฐ 10% ๋ฏธ๋งŒ
์–ต์ œ ๋ฐ€๋„์ฝ”๋“œ 1,000์ค„๋‹น ์–ต์ œ ํšŸ์ˆ˜์ƒ์Šน ์ถ”์„ธ๋Š” ์ฒด๊ณ„์ ์ธ ์˜ค๋ฅ˜์œจ ๋ฌธ์ œ์ด๋ฏ€๋กœ ๊ทœ์น™ ์กฐ์ •์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
๋ฌธ์ œ ๋ฐœ๊ฒฌ ๋Œ€ ํ•ด๊ฒฐ ๋น„์œจํ™•์ •๋œ ๊ฒ€์‚ฌ ๊ฒฐ๊ณผ / ์ด ๊ฒ€์‚ฌ ๊ฒฐ๊ณผ๋น„์œจ ์ƒ์Šน = ๋„๊ตฌ ์‹ ๋ขฐ๋„ ํ–ฅ์ƒ
์กฐ์‚ฌํ•  ์‹œ๊ฐ„๊ฐœ๋ฐœ์ž๊ฐ€ ๋ฐœ๊ฒฌ ์‚ฌํ•ญ๋‹น ์†Œ์š”ํ•˜๋Š” ํ‰๊ท  ์‹œ๊ฐ„์‹œ๊ฐ„์ด ์ง€๋‚จ์— ๋”ฐ๋ผ ๊ฐ์†Œํ•˜๋Š” ๊ฒƒ์€ FP ๋น„์œจ์ด ๊ฐœ์„ ๋จ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

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

ํ•ต์‹ฌ ์›์น™: ๋ฌธ์„œํ™” ์—†์ด ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์œผ๋กœ ๋ฐฐํฌ๋˜๋Š” ์˜ค๋ฅ˜ ์ˆ˜์ •์€ ๊ธฐ์ˆ ์  ๋ถ€์ฑ„์ž…๋‹ˆ๋‹ค. ๋ชจ๋“  ์˜ค๋ฅ˜ ์ˆ˜์ •์—๋Š” ๋‹จ์ˆœํžˆ ์˜ค๋ฅ˜ ์ˆ˜์ • ์‚ฌ์œ ๋ฅผ ์„ค๋ช…ํ•˜๋Š” ์ฃผ์„์ด ํฌํ•จ๋˜์–ด์•ผ ํ•˜๋ฉฐ, ๋‹จ์ˆœํžˆ ์˜ค๋ฅ˜ ์ˆ˜์ • ์‚ฌ์œ ๋ฅผ ๋‚˜์—ดํ•˜๋Š” ๊ฒƒ๋งŒ์œผ๋กœ๋Š” ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. NOSONAR ์ฃผ์„.

๋ฐฉ๋ฒ• SMART TS XL ๊ตฌ์กฐ ๋ถ„์„์„ ํ†ตํ•ด ์˜คํƒ์„ ์ค„์ž…๋‹ˆ๋‹ค.

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

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

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

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

์‹ ๋ขฐ๊ฐ€ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ์ฒ™๋„์ž…๋‹ˆ๋‹ค.

์˜คํƒ ๊ฐ์†Œ ํ”„๋กœ๊ทธ๋žจ์˜ ์„ฑ๊ณต ์—ฌ๋ถ€๋Š” ์˜คํƒ๋ฅ  ์ž์ฒด๋กœ ์ธก์ •๋˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ๋ถ„์„ ๊ฒฐ๊ณผ์— ๋Œ€ํ•œ ๊ฐœ๋ฐœ์ž์˜ ์‹ ๋ขฐ๋„๋กœ ํ‰๊ฐ€๋ฉ๋‹ˆ๋‹ค. ๋„๊ตฌ๊ฐ€ ์‹ค์ œ ๋ฌธ์ œ๋ฅผ ์ •ํ™•ํ•˜๊ฒŒ ํ‘œ์‹œํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ๋ชจ๋“  ๋ฐœ๊ฒฌ ์‚ฌํ•ญ์„ ์ฒ ์ €ํžˆ ์กฐ์‚ฌํ•˜๋Š” ํŒ€์€ ์ •์  ๋ถ„์„์„ ํ†ตํ•ด ๊ฐ€์น˜๋ฅผ ์–ป๋Š” ํŒ€์ž…๋‹ˆ๋‹ค. ๋ฐ˜๋Œ€๋กœ, ๊ณผ๊ฑฐ์— ๋Œ€๋ถ€๋ถ„์˜ ๋ฐœ๊ฒฌ ์‚ฌํ•ญ์ด ์˜คํƒ์ด์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฅผ ๋ฌด์‹œํ•˜๋Š” ํŒ€์€ ๋ถ„์„ ํ”„๋กœ๊ทธ๋žจ์ด ์ด๋ฏธ ์‹คํŒจํ•œ ๊ฒƒ์ด๋‚˜ ๋‹ค๋ฆ„์—†์Šต๋‹ˆ๋‹ค.

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