결함 밀도 (Defect Density) 측정 및 테스트 프로세스 통제
핵심 인사이트 (3줄 요약)
- 본질: 결함 밀도(Defect Density)는 발견된 총 버그의 개수를 소프트웨어의 크기(KLOC, 천 줄의 코드) 또는 기능 점수(Function Point)로 나눈 객관적 품질 지표로, 단순히 "버그가 몇 개냐?"를 넘어 "코드 1,000줄당 버그가 몇 개나 튀어나오는가?"를 측정하는 소프트웨어 품질의 절대 밀도계다.
- 가치: 100줄짜리 코드에서 버그 10개가 나온 것과, 10만 줄짜리 코드에서 버그 10개가 나온 것은 하늘과 땅 차이다. 결함 밀도는 서로 덩치가 다른 모듈이나 부서 간의 개발 실력(Quality)을 공평하게 비교하게 해 주며, "결함 밀도가 일정 수치 이하로 떨어져야만 운영(Production) 배포를 승인한다"는 **테스트 종료 조건(Exit Criteria)**의 수학적 근거를 제공한다.
- 융합: 실무에서는 단순히 숫자를 재는 것을 넘어 정적 분석기(SonarQube)와 결함 생명주기 관리 도구(Jira) 시스템과 융합되어, 특정 모듈의 결함 밀도가 갑자기 치솟을 때(Spike) "저 모듈은 스파게티 코드이니 즉각 리팩토링을 지시하라"는 아키텍트의 의사결정(통계적 프로세스 통제, SPC) 지표로 활약한다.
Ⅰ. 개요 및 필요성 (Context & Necessity)
-
개념: 결함 밀도 공식은
결함 수 / 소프트웨어 크기다. 예를 들어 로그인 모듈(10,000줄)에서 버그가 20개 나왔다면, 이 모듈의 결함 밀도는20 / 10 KLOC = 2.0 (버그/KLOC)이다. 즉, 1천 줄당 버그가 2개씩 튀어나온다는 뜻이다. -
필요성: 프로젝트 오픈이 3일 남았다. A팀이 "우리 팀은 어제 버그를 100개나 잡았어요! 열심히 일했죠?"라고 자랑한다. B팀은 "우린 5개밖에 못 잡았네요"라고 풀이 죽었다. 사장님은 A팀을 칭찬해야 할까? 아니다. A팀이 만든 앱의 크기가 고작 5,000줄(버그 밀도 20.0)이고, B팀이 만든 시스템이 100만 줄(버그 밀도 0.005)이라면 A팀은 상을 받을 게 아니라 당장 해고당해야 할 쓰레기 코더들이다. 이처럼 소프트웨어의 '부피'를 무시한 단순한 '결함 갯수'는 경영진의 눈을 가리는 사기극이 되기 때문에, 동일한 체급(KLOC)에서 누가 진짜 깨끗한 코드를 짜는지 가려낼 공학적 지표(밀도)가 절대적으로 필요했다.
-
💡 비유: 도시의 '인구 밀도'를 계산하는 것과 같습니다.
- 단순 결함 수 (절대 평가): 몽골에는 사람이 300만 명 살고, 홍대 입구에는 10만 명의 사람이 있습니다. "몽골에 사람이 더 많으니 몽골이 더 복잡하네!"라고 말하면 바보입니다.
- 결함 밀도 (상대 평가): 몽골은 땅(소프트웨어 크기)이 엄청나게 넓어서 인구 밀도가 '1제곱킬로미터당 2명'입니다(아주 쾌적하고 깨끗한 코드). 반면 홍대는 땅이 코딱지만 한데 10만 명이 몰려있어 '1제곱킬로미터당 2만 명'입니다(스파게티 코드, 끔찍한 버그 밭). 땅 크기로 나눠서 계산해야만 진짜 '복잡도와 위험도'를 100% 꿰뚫어 볼 수 있습니다.
-
등장 배경 및 발전 과정:
- 초기 코드 라인 수(LOC) 측정 (1970년대): S/W 공학 초기, 생산성을 그저 "하루에 코드 몇 줄 짰냐"로 계산하던 시절, 버그도 단순 LOC 대비 비율로 측정하기 시작함.
- 기능 점수(FP)의 편입 (1980년대): 자바 1줄과 어셈블리어 1줄은 밀도가 다르다! 언어에 종속되지 않는 진정한 크기 측정법인 '기능 점수(Function Point)'가 결함 밀도 공모의 분모로 차용되며 정밀해짐.
- 통계적 프로세스 통제(SPC) 시대 (현재): 결함 밀도 지표가 식스시그마(Six Sigma)나 애자일 CI/CD 품질 게이트(Quality Gate)의 자동 통과 커트라인으로 융합되어 인간의 감정 개입 없는 자동화된 릴리스 판독기로 진화.
-
📢 섹션 요약 비유: 수박에 씨(버그)가 100개 있는 것과 포도알에 씨가 10개 있는 것을 비교할 때, 수박이 씨가 더 많다고 버리기엔 수박의 크기(코드)가 훨씬 큽니다. 과일의 부피 대비 씨앗이 얼마나 징그럽게 박혀있는지 정밀하게 계산해 포도알(위험한 모듈)을 뱉어내는 과일 품질 감별 공식입니다.
Ⅱ. 아키텍처 및 핵심 원리 (Deep Dive)
결함 밀도 (Defect Density) 산출 메커니즘
어떻게 분자(버그)와 분모(크기)를 잡아내어 하나의 점수로 만들까?
┌───────────────────────────────────────────────────────────────┐
│ 결함 밀도 (Defect Density) 측정 수식과 적용 파이프라인 │
├───────────────────────────────────────────────────────────────┤
│ │
│ [ 1단계: 분모 (소프트웨어의 덩치 구하기) ] │
│ - 측정법 A (KLOC): "이 모듈은 50,000줄이야. (50 KLOC)" │
│ (단점: 개발자가 쓸데없이 줄바꿈만 많이 하면 덩치가 커 보여서 사기침)│
│ - 측정법 B (FP, 기능점수): "이 모듈은 화면 3개, DB 2개니까 100 FP야"│
│ (장점: 코딩 언어가 파이썬이든 자바든 공평하게 측정됨!) │
│ │
│ [ 2단계: 분자 (결함의 갯수 구하기) ] │
│ - 테스트를 통해 발견된 모든 버그의 수를 더한다. (예: 200개) │
│ - 🚨 주의: 사소한 오타 버그와 치명적 서버 다운 버그를 똑같이 1개로 치면 │
│ 왜곡 발생! 가중치(치명 5점, 일반 1점)를 곱하는 튜닝 필수! │
│ │
│ [ 3단계: 나눗셈 (결함 밀도 산출) ] │
│ - KLOC 기준: 200개 / 50 KLOC = 4.0 (천 줄당 4개의 버그) │
│ - FP 기준 : 200개 / 100 FP = 2.0 (기능 점수 1점당 2개의 버그)│
│ │
│ [ 4단계: 프로세스 통제 및 액션 (Control Action) ] │
│ ▶ 사내 기준 커트라인이 "KLOC당 1.0 이하" 라면? │
│ ▶ 현재 이 모듈은 4.0으로 쓰레기 상태! ─▶ 릴리스(배포) 무조건 차단(Stop)│
│ ▶ 즉시 해당 모듈 개발자들에게 코드 전면 재점검(Inspection) 지시! │
└───────────────────────────────────────────────────────────────┘
[다이어그램 해설] 결함 밀도는 일종의 '통계적 관리도(Control Chart)'를 그리는 데 사용된다. 만약 A 모듈의 결함 밀도가 0.5, B 모듈이 0.7인데 갑자기 C 모듈에서 결함 밀도가 15.0이 찍히며 하늘을 뚫고 솟구쳤다(Spike)고 해보자. 이것은 개발자의 컨디션 탓이 아니다. 애초에 C 모듈의 요구사항이 쓰레기처럼 모호하게 짜여 있었거나, 복잡도(Cyclomatic Complexity)가 비정상적으로 높아서 건드리기만 하면 터지는 지뢰밭일 확률이 99%다. 아키텍트는 밀도 그래프가 미친 듯이 튀는 이 '파레토(Pareto)의 불량 구역'을 발견하는 즉시 수술용 메스(리팩토링)를 들이대야 한다.
Ⅲ. 실무 적용 및 기술사적 판단
실무 시나리오
-
시나리오 — 릴리스(Release) 판정 회의에서의 감정싸움 붕괴: 대규모 뱅킹 시스템 오픈 전날. 사장님 주재 '오픈 여부 판정 회의'가 열렸다. 영업팀은 "당장 내일 오픈 안 하면 회사 망합니다. 사소한 버그는 나중에 고치고 강행합시다!"라고 소리치고, QA팀은 "어제도 버그가 50개나 나왔어요! 오픈하면 대형 사고 납니다!"라고 반대한다. 사장님은 "50개면 많은 거야 적은 거야?"라며 헷갈려 결정을 못 내린다.
- 판단: 정량적인 **테스트 종료 조건(Exit Criteria)**을 사전에 협의해 놓지 않아 발생한 주먹구구식 감정싸움이자 통제력 상실의 전형이다.
- 해결책: 프로젝트 극초기부터 **'결함 밀도(Defect Density) KPI'**를 헌법으로 선포해야 한다. "우리 시스템 총규모는 100만 줄(1,000 KLOC)이다. 글로벌 금융 표준에 따라, 오픈 직전 잔존 결함 밀도는 무조건
0.1 버그/KLOC이하여야만 한다. 즉 전체 버그가 100개 미만으로 떨어져야만 오픈한다!"라고 못을 박는다. 어제 버그가 50개가 나왔다면, 50개는 100개 커트라인 안에 들어오므로, QA팀의 불안감을 엑셀 데이터(정량 지표)로 찍어 누르고 객관적이고 쿨하게 "오픈 Go!" 스위치를 누를 수 있는 절대적 권위(Authority)를 확보하게 된다.
-
시나리오 — 언어 의존적 KLOC의 착시와 섀도우 IT: SI 프로젝트에서 A외주업체는 자바(Java)로 게시판 10개를 짰고, B외주업체는 파이썬(Python)으로 비슷한 게시판 10개를 짰다. A업체의 코드는 10,000줄(10 KLOC)이었고 버그가 10개 나왔다 (밀도 1.0). B업체 코드는 2,000줄(2 KLOC)이었고 똑같이 버그가 10개 나왔다 (밀도 5.0). 갑자기 감리단이 B업체에게 "밀도가 5배나 높다! 코드 품질이 쓰레기니 돈을 깎겠다"고 시비를 걸었다.
- 판단: KLOC(천 줄)라는 잣대는 언어의 표현력(Expressiveness)을 무시하는 심각한 왜곡(Bias)을 유발한다. 파이썬이 자바보다 코드가 5배 짧은 건 당연한데, 이걸 똑같은 KLOC로 나누면 코드를 효율적으로 짧게 짠 B업체가 오히려 버그 밀도가 5배 높아 보이는 끔찍한 역차별을 당하게 된다.
- 해결책: 이기종 언어나 프레임워크가 섞여 있는 현대 MSA 아키텍처 환경에서는 KLOC를 결함 밀도의 분모로 쓰면 안 된다. 무조건 **기능 점수(FP, Function Point)**로 전환해야 한다. "게시판 10개를 짰으니 너희 둘 다 똑같은 100 FP다." 이렇게 뼈대(기능의 복잡도)를 기준으로 분모를 공평하게 맞추면, 양쪽 모두
10버그 / 100 FP = 0.1로 완벽하게 동일하고 공정한 결함 밀도 성적표를 받게 되어 억울한 하도급 분쟁을 원천 차단할 수 있다.
도입 체크리스트
- 시딩(Seeding) 버그 꼼수: 결함 밀도가 낮게 나오려면 두 가지 방법이 있다. 첫째, 진짜 코드를 잘 짜는 것. 둘째, 테스터가 놀고먹어서 버그를 아예 못 찾는 것이다. 결함 밀도가 낮게 나왔다고 무조건 기뻐하면 안 된다. 테스터가 바보인지 확인하기 위해, 아키텍트가 몰래 소스 코드에 일부러 '가짜 버그(Seeded Defect)' 10개를 심어놓아야 한다(오류 파종). 결함 밀도 측정 기간에 테스터가 이 가짜 버그 10개 중 9개를 잡아냈다면(90% 탐지율), 그제야 테스터의 실력을 믿고 결함 밀도 점수에 도장을 찍어줄 수 있다.
Ⅳ. 기대효과 및 결론
정량/정성 기대효과
| 구분 | 단순 결함 수(Count) 집계 방식 | 결함 밀도(Density) 및 통계적 통제 | 비즈니스 관리 품질 혁신 효과 |
|---|---|---|---|
| 정량 (품질 비교) | 시스템 크기가 달라서 타 부서와 비교 불가 | KLOC/FP 기반으로 전 부서 객관적 절대 랭킹 도출 | 품질 불량 조직(팀)의 정확한 색출 및 리소스 투입 |
| 정량 (배포 안정성) | "버그 100개면 많은 건가?" 임원진 판단 불가 | "밀도 0.5 이하 합격"이라는 명확한 수치 산정 | 릴리스 판정(Go/No-go) 회의 시간 99% 단축 |
| 정성 (개발 문화) | 버그 숨기기에 급급, 쓸데없는 코드 부풀리기 | 결함의 발생 구역(Hotspot) 파악에 집중 | 통계(데이터)가 지배하는 데브옵스 품질 게이트 정착 |
"측정할 수 없다면 관리할 수 없다(You can't manage what you can't measure)." 피터 드러커의 이 명언은 소프트웨어 결함 밀도의 본질을 관통한다. 100만 줄의 거대한 모놀리식 코드가 돌아가는 서버는 인간의 눈으로 들여다볼 수 없는 캄캄한 심연이다. 결함 밀도는 이 심연 속에서 "현재 암세포(버그)가 1제곱센티미터당 몇 개나 징그럽게 퍼져있는지" 엑스레이(X-ray) 사진을 찍어 아키텍트의 모니터에 띄워주는 통계적 생명 유지 장치다. 기술사는 무턱대고 밤새워 버그를 잡으라고 소리치는 구시대적 채찍질을 멈추고, 결함 밀도 그래프의 스파이크(튀어 오름)를 분석해 "저 모듈은 태생부터 썩었으니 아예 뜯어서 재개발하라"고 메스를 긋는 차가운 통계적 품질 외과 의사가 되어야 한다.
📌 관련 개념 맵 (Knowledge Graph)
| 개념 명칭 | 관계 및 시너지 설명 |
|---|---|
| KLOC (Kilo Lines of Code) | 1,000줄의 코드 덩어리. 결함 밀도의 제일 만만한 분모. C언어 시절엔 최고였으나, 엔터를 치면 줄이 늘어나는 꼼수와 언어 간의 불평등 문제로 점점 은퇴하고 있는 잣대다. |
| 기능 점수 (Function Point, FP) | 코드 줄수(KLOC)의 억울함을 씻어주는 분모의 제왕. 코드를 파이썬으로 짰든 어셈블리로 짰든 상관없이, "이 화면에서 버튼 3개 눌리고, DB에 글 1개 써지니까 넌 무조건 50점이야"라고 뼈대만 평가해 주는 가장 공정한 저울. |
| 통계적 프로세스 통제 (SPC) | 결함 밀도를 엑셀표로 쫙 그려놓고, 위아래로 한계선(Control Limit)을 그어두는 마법. 선을 뚫고 올라가는 놈은 우연이 아니라 시스템이 고장 난 거니까 당장 수술해야 한다는 도요타 공장식 품질 관리. |
| 오류 추정 (Error Seeding) | 밀도가 너무 예쁘게 낮게 나오면 "테스터들이 노는 거 아냐?" 하고 의심할 때, 일부러 코드에 독(가짜 버그)을 심어놓고 얼마나 잘 찾아내는지 역으로 사냥개를 테스트하는 기법. |
| Exit Criteria (테스트 종료 조건) | 끝이 없는 테스트 지옥에서 벗어나 "이제 그만 집에 가자"고 선언할 수 있는 방 빼는 기준. "전체 모듈 결함 밀도가 0.2 KLOC 이하로 떨어지면 묻지도 따지지도 않고 퇴근!"이라는 피의 서약이다. |
👶 어린이를 위한 3줄 비유 설명
- A 농장에선 썩은 사과가 10개 나왔고, B 농장에서도 썩은 사과가 10개 나왔어요. 사람들은 "둘 다 썩은 사과가 10개니까 똑같이 나쁜 농장이네!"라고 말했어요.
- 하지만 이건 바보 같은 생각이에요! 알고 보니 A 농장은 사과나무가 딱 1그루(코드가 작음)뿐이었고, B 농장은 사과나무가 무려 10만 그루(거대한 시스템)나 되는 초대형 농장이었거든요!
- 나무 1그루에서 10개가 썩은 A 농장은 진짜 최악의 쓰레기 농장이고, 10만 그루 중에 고작 10개 썩은 B 농장은 천재적인 농장이에요. 이렇게 나무 크기(소프트웨어 덩치)를 기준으로 썩은 사과의 진짜 심각성을 나누기해서 공평하게 평가하는 게 '결함 밀도'랍니다!