4.4 정적 분석과 코드 스멜 메트릭
개요 및 동기
정적 분석 도구는 소스 코드를 실행하지 않고 훑으며, 결함, 보안 취약점, 혹은 유지보수성 문제와 상관관계가 있다고 알려진 패턴을 표시한다: 도달할 수 없는 코드, 닫히지 않은 자원, 의심스러운 타입 강제 변환, 중복된 논리, 그리고 반드시 버그는 아니지만 코드를 이해하거나, 테스트하거나, 안전하게 변경하기 더 어렵게 만드는 경향이 있는 구조적 패턴인 코드 스멜이라는 더 넓은 범주. 정적 분석은 이 부의 다른 주제에 있는 더 목표를 겨냥한 메트릭 아래에 있는 자동화되고 지속적인 계층이며, 모든 커밋에서 실행되어 주기적인 감사를 기다리는 대신 문제가 도입되는 순간 드러낸다.
이 주제의 핵심 관심사는 정적 분석 도구가 보고하는 것과 실제로 중요한 것 사이의 간극이다. 도구는 대규모 코드베이스에 걸쳐 수천 개의 발견 사항을 표시할 수 있으며, 발견 사항의 수 홀로는 빈약한 메트릭인데, 그것이 사소한 스타일 선호와 진정하고 심각한 위험을 뒤섞고, 실제 수정을 통해서만큼이나 억제를 통해서도 쉽게 줄어들 수 있기 때문이다. 정적 분석의 가치는 원시 발견 사항 수가 아니라 조직이 얼마나 잘 심각도를 트리아지하고, 퇴보를 막고, 도구의 판단을 사람의 리뷰를 보완하는 것이 아니라 그것을 대체하는 것으로 취급하려는 유혹에 저항하는지에서 온다.
대규모 팀에게 정적 분석은 어떤 팀도 완전히 수동으로 리뷰할 수 없을 만큼 큰 코드베이스에 걸쳐 코드 품질과 보안 위생의 기준선을 시행하는 유일하게 실용적인 방법이다. 흔히 안전한 코딩 관행에 관한 준수 요건에 직면하는 엔터프라이즈와 정부 조직은, 사람 리뷰어가 우연히 문제를 알아챘을 때만이 아니라 일관되게 기준선 수준의 정밀 조사가 적용되었다는 문서화되고 감사 가능한 증거로서 정적 분석에 의존한다.
핵심 원칙
- 원시 발견 사항 수는 그 자체로 빈약한 메트릭이다. 그것은 사소한 문제와 심각한 문제를 뒤섞으며, 진정한 수정이 아니라 억제를 통해 게임당할 수 있다.
- 심각도 트리아지가 물량보다 더 중요하다. 소수의 치명적인 발견 사항은 다수의 사소한 발견 사항보다 더 많은 관심을 받을 자격이 있다.
- 정적 분석은 사람의 리뷰를 보완하지, 대체하지 않는다. 도구는 패턴을 잡아내지만 의도나 비즈니스 맥락을 이해하지 못한다.
- “새로 도입된 문제” 추세는 총 백로그 수보다 더 실행 가능하다. 그것은 현재 관행이 개선되고 있는지 퇴보하고 있는지 알려준다.
- 거짓 양성은 도구에 대한 신뢰를 침식한다. 관리되지 않는 거짓 양성률은 팀이 실제 발견 사항을 포함해 발견 사항을 통째로 무시하게 만든다.
권장 사항
원시 개수가 아니라 심각도 가중 발견 사항을 추적하라
당신의 정적 분석 도구를 심각도(치명적, 높음, 중간, 낮음, 혹은 그와 동등한 척도)로 발견 사항을 분류하도록 구성하고, 평평한 총 개수가 아니라 심각도 가중 추세를 추적하라. 치명적인 발견 사항이 0개이고 낮은 심각도의 스타일 제안이 500개인 코드베이스는 치명적인 발견 사항이 50개이고 스타일 문제가 전혀 없는 코드베이스와 매우 다른 상태에 있으며, 원시 개수는 그렇지 않음에도 이 둘을 대략 동등하게 취급한다.
전체 역사적 백로그가 아니라 새로 도입된 발견 사항에 게이트를 걸라
대부분의 확립된 코드베이스는 현재 관행보다 앞선, 한꺼번에 고치기에는 엄청나게 비쌀 발견 사항의 레거시 백로그를 지니고 있다. 전체 백로그가 정리될 때까지 모든 작업을 막는 대신, 특정 변경이 합의된 심각도 임계값 이상의 새로운 발견 사항을 도입하는지에 CI를 게이트하여, 더 이상의 축적을 막으면서 백로그가 정상적인 유지보수를 통해 점진적으로 줄어들게 하라. 이 구분은 주제 4.2의 커버리지 바닥 권장 사항을 반영한다: 비현실적이고 한꺼번에 하는 수정을 요구하는 대신 퇴보로부터 보호하라.
거짓 양성률을 능동적으로 관리하라
발견 사항의 표본을, 특히 물량이 많은 범주를 주기적으로 검토하고 얼마나 많은 것이 진정한 거짓 양성인지, 즉 도구가 맥락상 실제로는 문제가 되지 않는 패턴을 표시한 경우인지 확인하라. 팀이 출력의 너무 많은 부분이 잡음이라는 이유로 도구의 출력을 통째로 무시하는 습관을 발달시키게 두는 대신, 진정으로 시끄럽고 낮은 가치의 규칙 범주를 특별히 억제하도록 규칙 구성을 조정하라. 높고 관리되지 않는 거짓 양성률은 정적 분석 프로그램의 신뢰성을 파괴하는 단일한 가장 빠른 방법이다.
정적 분석 발견 사항을 자동 평결이 아니라 리뷰를 위한 신호로 사용하라
진정하고 거짓 양성이 아닌 발견 사항조차 항상 자동적이고 의무적인 수정을 요구하는 것은 아니다. 일부 표시된 패턴은 도구가 볼 수 없는 특정 맥락을 고려할 때 받아들일 수 있다. 모든 발견 사항을 맹목적으로 의무로 시행하거나 시간이 지남에 따라 도구의 가치를 침식하는 조용하고 문서화되지 않은 억제를 허용하는 대신, 사람이 문서화된 이유로 발견 사항을 리뷰하고 고치거나 명시적이고 눈에 보이게 면제하는 가벼운 절차를 구축하라.
정적 분석을 이 부의 다른 코드 품질 메트릭과 결합하라
정적 분석 발견 사항, 복잡도 점수(주제 4.1), 핫스팟 데이터(주제 4.3)는 경쟁하는 메트릭이 아니라 보완적인 증거다. 미해결 정적 분석 발견 사항이 높게 집중되어 있으면서 동시에 처닝-복잡도 핫스팟이기도 한 파일은 특별히 우선순위가 매겨진 관심을 받을 강력한 후보인데, 여러 독립적인 신호가 같은 결론으로 수렴하고 있기 때문이다.
트레이드오프: 장단점
| 접근법 | 장점 | 단점 |
|---|---|---|
| 메트릭으로서의 원시 발견 사항 수 | 보고하기 단순함 | 사소한 문제와 심각한 문제를 뒤섞음; 억제를 통해 쉽게 게임됨 |
| 심각도 가중 추세 | 실제 위험을 더 정확하게 반영함 | 지속적인 심각도 분류 유지 보수가 필요함 |
| 전체 역사적 백로그에 게이트 걸기 | 결국의 코드 청결도를 최대화함 | 확립된 코드베이스에는 흔히 비실용적임; 모든 작업을 멈출 수 있음 |
| 새로운 발견 사항에만 게이트 걸기 | 실용적이고, 퇴보를 막으며, 백로그가 점진적으로 줄어들게 함 | 레거시 문제가 의도적인 개선 계획 없이는 더 오래 지속됨 |
핵심 긴장은 철저함 대 실용성이다. 새로운 작업이 진행되기 전에 전체 역사적 백로그가 해결되어야 한다고 요구하는 정적 분석 정책은 철저하지만 실제 역사를 가진 어떤 코드베이스에도 보통 비실용적이며, 그 압박 아래 있는 팀은 진정으로 수정하는 대신 발견 사항을 통째로 억제하는 경향이 있다. 새로운 발견 사항에 엄격하게 게이트를 걸면서 이 주제와 주제 4.3이 권장하는 심각도와 교차 참조 기법을 사용해 우선순위가 매겨진 레거시 백로그에 대해 별도의 의도적으로 속도가 조절된 개선 노력을 운영함으로써 이 긴장을 해결하라.
팀과 논의할 질문
우리는 심각도 가중 추세를 추적하는가, 아니면 단지 원시 총 발견 사항 수를 추적하는가? 당신의 실제 대시보드를 가져와 확인하라. 많은 도구에서 원시 개수는 기본적으로 흔하며 대신 심각도를 제대로 드러내려면 흔히 의도적인 구성이 필요하다.
미해결 발견 사항의 우리 현재 레거시 백로그는 무엇이며, 우리는 그것을 줄이기 위한 의도적이고 속도가 조절된 계획을 가지고 있는가, 아니면 그것은 그저 무기한으로 축적되고 있는가? 다뤄지지 않고 조용히 자라나는 백로그는 흔하며 검토되지 않은 채 남겨 두는 대신 정직하게 이름 붙일 가치가 있다.
우리의 가장 물량이 많은 발견 사항 범주에 대한 우리의 추정 거짓 양성률은 무엇이며, 그에 대응해 규칙 구성을 조정했는가? 이것을 확인한 적이 없다면, 가장 시끄러운 범주에서 발견 사항 묶음을 표본으로 추출하고 얼마나 많은 것이 진정으로 실행 가능한지 정직하게 평가하라.
우리 팀의 엔지니어는 정적 분석 발견 사항을 신뢰하는가, 아니면 출력의 너무 많은 부분이 잡음이기 때문에 그것을 차단하는 법을 배웠는가? 이것은 팀에게 물어볼 가치가 있는 직접적이고 정직한 직감 확인 질문인데, 무시당하는 도구는 그 이론적 역량과 무관하게 아무런 실제 가치도 제공하지 않기 때문이다.
특정 맥락을 고려할 때 면제되어야 한다고 팀이 믿는 정당한 발견 사항을 우리는 현재 어떻게 다루는가? 당신의 절차가 이것을 눈에 보이고 문서화된 결정으로 만드는지, 아니면 시간이 지남에 따라 도구의 신호를 침식하는 조용하고 문서화되지 않은 억제를 통해 일어나는지 확인하라.
정적 분석 발견 사항, 복잡도 점수, 핫스팟 데이터가 같은 파일이나 모듈에서 수렴하는 곳은 어디인가? 이 세 가지 신호를 명시적으로 교차 참조하라. 여러 독립적인 메트릭에 걸친 수렴은 어느 하나 홀로보다 더 강한 우선순위 지정 신호다.
분야별 관점
스타트업. 처음부터 CI에 통합된 가볍고 무료인 정적 분석 도구는 저렴한 보험이며 레거시 백로그가 축적될 기회를 갖기 전에 진정한 문제를 일찍 잡아낸다. 즉시 이용 가능한 모든 규칙을 활성화하는 대신 규칙 집합을 진정으로 가치가 높고 잡음이 적은 범주에 집중되게 유지하라.
중소기업. 대부분의 현대적인 언어 생태계는 유능한 무료 정적 분석 도구를 포함한다. 합리적인 기본 규칙 집합으로 CI에서 그것을 활성화하는 데는 거의 투자가 필요하지 않다. 기존 백로그를 한꺼번에 해결하려고 시도하는 대신 새로운 발견 사항에 게이트를 거는 데 집중하라.
엔터프라이즈. 이 규모에서는 거짓 양성률과 심각도 트리아지를 의도적으로 관리하는 것이 필수적인데, 잘 조정되지 않은 도구가 수십 개 팀에 걸쳐 과도한 잡음을 만들어 내면 조직 전체에서 무시될 것이기 때문이다. 규칙 조정을 일회성 설정 작업이 아니라 지속적인 규율로 취급하며, 정적 분석 도구 구성 자체를 위한 전담 소유자에 투자하라.
정부. 특히 보안 관련 정적 분석 발견 사항은 흔히 준수 및 감사 요건에 직접 관련된다. 발견 사항이 어떻게 트리아지되고, 고쳐지고, 혹은 기록된 정당화와 함께 공식적으로 면제되는지에 대한 문서화되고 감사 가능한 절차를 유지하라. 이 문서화 자체가 흔히 외부 감사자가 보고 싶어 하는 것이기 때문이다.
사례
엔터프라이즈. 한 소프트웨어 회사의 정적 분석 대시보드는 몇 년 동안 심각도 가중 트리아지 없이 코드베이스에 걸쳐 4만 개가 넘는 미해결 발견 사항을 축적해 왔으며, 그 수는 너무 커서 엔지니어들이 대체로 그 대시보드를 전혀 보지 않게 되었다. 개정된 접근법은 발견 사항을 심각도별로 분류했고, 진정으로 치명적인 것은 200개 미만이라는 것을 발견했으며, 낮은 심각도 백로그가 정상적인 코드 유지보수를 통해 점진적으로 줄어들도록 두면서 특별히 새로운 치명적이고 높은 심각도의 발견 사항에 CI를 게이트했다. 6개월 안에 치명적인 발견 사항은 한 자릿수로 떨어졌고, 더 중요하게는, 엔지니어 설문 데이터는 이제 도구가 압도적이고 무시되는 백로그가 아니라 관리 가능하고 진정으로 실행 가능한 신호를 드러냈기 때문에 그 출력에 대한 신뢰가 회복되었다는 것을 보여 주었다.
정부. 한 국방 기관의 소프트웨어 공급망 보안 정책은 어떤 릴리스든 하기 전에 미해결 발견 사항이 전혀 없는 정적 분석 스캔을 요구했으며, 이 정책은 실무에서 개발 팀이 단지 실행 불가능한 전부 아니면 전무 게이트 아래서 출시 마감일을 맞추기 위해 일부 진정한 보안 문제를 포함해 많은 수의 발견 사항을 억제하게 만들었다. 개정된 정책은 어떤 주어진 릴리스에서든 새로운 치명적이거나 높은 심각도의 발견 사항이 전혀 없을 것을 요구했으며, 레거시 백로그에 대해 보안 거버넌스 위원회가 분기별로 검토하는 문서화되고 추적되는 개선 계획 및 일정과 결합되었다. 이 실용적이고 단계적인 접근법은 새로운 코드에 대한 진정한 보안 정밀 조사를 회복시키는 동시에 주로 진정한 수정보다 억제를 만들어 냈던 이전의 실행 불가능한 정책과 달리 18개월에 걸쳐 레거시 백로그에 대한 실제적이고 측정 가능한 진전을 만들어 냈다.
비즈니스 사례: 동기, ROI, TCO
잘 관리된 정적 분석의 수익은 실제 결함과 보안 취약점이 프로덕션에 도달하기 전에 그것들을 잡아내는 것이며, 같은 커버리지를 위해 동등한 사람 리뷰 노력이 필요로 할 비용보다 훨씬 더 낮은 비용으로 그렇게 한다. 위의 국방 기관 사례는 이것을 잘못했을 때의 비용을 보여 준다: 실행 불가능한 전부 아니면 전무 정책은 그 의도와 정반대로 억제를 몰아붙임으로써 실제로 진정한 보안 정밀 조사를 줄였다.
총 소유 비용은 흔히 일반적인 언어 생태계에서는 무료이거나 저렴한 도구 자체와, 심각도 트리아지, 거짓 양성 관리, 레거시 백로그 개선 계획의 지속적인 규율을 포함한다. 도구 자체보다 그 지속적인 규율이야말로 정적 분석 프로그램이 진정하고 신뢰받는 가치를 제공하는지 아니면 무시되는 잡음으로 퇴화하는지를 결정한다.
안티패턴과 함정
- 원시 발견 사항 수를 메트릭으로 취급하기: 사소한 문제와 심각한 문제를 뒤섞으며 억제를 통해 쉽게 게임된다.
- 새로운 작업이 진행되기 전에 전체 역사적 백로그 해결을 요구하기: 보통 비실용적이며 진정한 수정보다 억제를 몰아붙인다.
- 거짓 양성률 무시하기: 관리되지 않는 잡음 수준은 팀이 실제 발견 사항을 포함해 도구의 출력을 완전히 차단하게 만든다.
- 정당한 발견 사항의 조용하고 문서화되지 않은 억제: 도구의 신호를 침식하고 준수 목적을 위한 감사 흔적을 남기지 않는다.
- 정적 분석 발견 사항을 사람의 리뷰 없는 자동 평결로 취급하기: 도구가 볼 수 없는 맥락을 놓친다.
- 발견 사항을 복잡도와 핫스팟 데이터에 비추어 결코 교차 참조하지 않기: 수렴하는 증거가 제공하는 더 강한 우선순위 지정 신호를 놓친다.
성숙도 모델
- 1단계, 시작: 정적 분석이 실행되지 않거나, 심각도 트리아지나 추세 추적 없이 발견 사항이 관리되지 않은 채 축적된다.
- 2단계, 개발: 일부 정적 분석이 CI에서 실행되지만, 심각도 트리아지가 일관성이 없고 거짓 양성률이 관리되지 않는다.
- 3단계, 표준화: 발견 사항이 심각도 가중되며 CI는 조직 전체에서 새로운 치명적이고 높은 심각도의 발견 사항에 게이트를 건다.
- 4단계, 관리: 거짓 양성률이 능동적으로 조정되고, 레거시 백로그는 문서화되고 속도가 조절된 개선 계획을 가지며, 면제는 눈에 보이고 문서화된다.
- 5단계, 조율: 정적 분석 발견 사항, 복잡도 데이터, 핫스팟 데이터가 투자 우선순위를 정하기 위해 일상적으로 교차 참조되며, 조직은 그 프로그램으로 거슬러 올라가는 구체적이고 측정 가능한 결함이나 보안 개선을 제시할 수 있다.
논의를 위한 아이디어
- 우리의 현재 심각도 가중 추세는 무엇이며, 그것은 개선되고 있는가 악화되고 있는가?
- 우리의 레거시 발견 사항 백로그는 얼마나 크며, 우리는 그것을 줄이기 위한 의도적인 계획을 가지고 있는가?
- 우리의 가장 시끄러운 발견 사항 범주에 대한 우리의 추정 거짓 양성률은 무엇인가?
- 우리 팀의 엔지니어는 현재 우리의 정적 분석 출력을 신뢰하는가 무시하는가?
- 우리 코드베이스에서 정적 분석 발견 사항이 복잡도나 핫스팟 데이터와 수렴하는 곳은 어디인가?
핵심 요약
- 사소한 문제와 심각한 문제를 뒤섞는 원시 발견 사항 수가 아니라 심각도 가중 추세를 추적하라.
- 비현실적인 한꺼번에 하는 수정을 요구하지 않으면서 퇴보를 막기 위해 전체 역사적 백로그가 아니라 새로 도입된 발견 사항에 CI를 게이트하라.
- 거짓 양성률을 능동적으로 관리하라. 관리되지 않는 잡음은 도구에 대한 신뢰를 파괴하고 발견 사항이 통째로 무시되게 만든다.
- 발견 사항을 자동 평결이나 조용한 억제가 아니라 눈에 보이고 문서화된 면제와 함께 사람의 리뷰를 위한 신호로 취급하라.
- 수렴하고 더 강한 우선순위 지정 증거를 위해 정적 분석을 복잡도와 핫스팟 데이터(주제 4.1, 주제 4.3)와 교차 참조하라.
참고 문헌 및 추가 자료
- Møller, Anders, and Michael I. Schwartzbach. Static Program Analysis. Department of Computer Science, Aarhus University.
- OWASP Foundation. Static application security testing (SAST) guidance.
- Fowler, Martin. Refactoring: Improving the Design of Existing Code. Addison-Wesley, 1999.
- Feathers, Michael. Working Effectively with Legacy Code. Prentice Hall, 2004.