-
코드의 어두운 구석을 드러내기 — radon을 통한 순환 복잡도 지표 수집IT 2026. 6. 4. 21:00
코드의 복잡도는 보이지 않는 빚(Technical Debt)이다. 여러 명이 오랫동안 수정한 소스코드에는 유독 분기문과 루프가 복잡하게 얽혀, 한 번 손대면 어디가 깨질지 모르는 "위험한 함수"들이 생기기 마련이다. 사람은 직관적으로 이 영역을 피하거나 조심할 수 있지만, 지식베이스의 문서를 RAG로 입력받아 소스코드를 고치는 AI 에이전트에게는 보이지 않는 지뢰밭과 같다.
코드 전체의 구조를 그리는 Stage A와 B를 마쳤다면, 이제 이 코드 구조의 품질 상태를 위키에 명시해 에이전트가 지식의 정확성과 코드 위험을 입체적으로 볼 수 있게 해야 한다.
deep-wikiStage C의 후보 도구인 radon은 소스코드를 정적 분석하여 함수별 순환 복잡도(Cyclomatic Complexity)를 숫자로 나타내는 역할을 맡는다.1. 왜 radon인가: 분기와 인지 과부하의 자동 측정
소스 코드가 복잡하다는 감각은 주관적이다. 하지만 Thomas J. McCabe가 제안한 순환 복잡도(Cyclomatic Complexity) 지표를 사용하면 이를 수학적이고 객관적인 정량 수치로 변환할 수 있다. radon은 파이썬 소스 파일을 AST로 파싱하여 이 계산 작업을 신속하게 해내는 가벼운 도구다.
- McCabe Metrics: 코드의 제어 흐름 그래프(Control Flow Graph)에서 선형 독립적인 경로의 수를 계산한다. 쉽게 말해 조건문(`if`, `elif`), 루프(`for`, `while`), 예외 처리(`try-except`) 블록이 늘어날수록 복잡도 점수가 1점씩 올라간다.
- Refactoring Guide: 복잡도에 따라 A(매우 단순함)부터 F(극도로 복잡함, 리팩토링 필수)까지 등급을 매겨 준다. 등급을 통해 어떤 함수가 잠재적 버그의 온상인지를 한눈에 식별할 수 있다.
- Low Overhead: 파이썬 빌트인 AST 파서 수준에서 빠르게 분기 노드를 카운트하므로 대규모 저장소 스캔 시 파이프라인 지연을 초래하지 않는다.
이름 자체에도 의도적인 메타포가 있다. 저자(Michele Lacchia)가 공식적으로 설명한 적은 없지만, 동반 도구를 xenon(크세논)으로 명명한 데서 패턴이 드러난다. 라돈(Rn, 원소 86번)은 무색·무취의 방사성 기체로, 건물 안에 쌓여도 측정 장비 없이는 존재조차 알 수 없다. 코드 복잡도도 마찬가지다 — 런타임 에러 없이 조용히 쌓이다가 어느 순간 수정 불가 수준으로 번진다. xenon은 radon 측정값 위에 임계값 강제(threshold enforcement)를 얹는 래퍼 도구인데, 라돈 검출기 위에 경보 장치를 얹는 구조와 정확히 맞아떨어진다. "보이지 않는 위험을 수치로 드러내는 도구"라는 설계 의도가 이름에 그대로 담겨 있는 셈이다.
2. 작동 원리: 제어 흐름의 갈래 계산
radon은 파이썬 파일의 AST 노드를 돌며 제어 흐름 분기를 파악한다. 함수 정의 내에 존재하는 복잡도 기여 노드들의 총합에 기초 상숫값 1을 더해 점수를 산출한다.
예를 들어, 내부에 `if` 조건문이 2개 있고 `for` 루프가 1개 있다면 해당 함수의 복잡도 점수는 `1(기본값) + 2(if) + 1(for) = 4`점이 된다. 이 점수를 기반으로 등급이 결정되어 위키 메타데이터로 전달된다.
3. Stage C 핵심 구현 예시
radon라이브러리를 활용해 파이썬 파일 내 개별 함수의 순환 복잡도를 추출하는 간결한 구현체다.from radon.visitors import ComplexityVisitor from radon.complexity import rank def analyze_function_complexity(source_code: str): # ComplexityVisitor를 생성해 AST를 순회하며 복잡도 분석 visitor = ComplexityVisitor.from_code(source_code) results = [] for block in visitor.blocks: # block은 Function 혹은 Class를 의미함 if block.type == "function": results.append({ "name": block.name, "complexity": block.complexity, "rank": rank(block.complexity), # A~F 등급 판정 "line": block.lineno }) return results # 분석 실행 예시 source = """ def process_data(data): if not data: return None results = [] for item in data: if item.is_valid: results.append(item.value) return results """ # process_data 복잡도 계산: 기본(1) + if(!data)(1) + for(1) + if(is_valid)(1) = 4 (Rank A) print(analyze_function_complexity(source))4. 우리 프로젝트에서의 효과와 가치
radon을 Stage C의 구성요소로 도입하면,
deep-wikiRAG 시스템은 다음과 같은 시너지 효과를 창출한다.첫째, AI 에이전트의 위험 인지 능력 향상이다. 위키 페이지의 메타데이터에 각 함수의 복잡도 등급이 `rank: F` 형태로 제공되면, 에이전트는 코드 수정을 제안할 때 "해당 함수는 순환 복잡도가 F 등급(점수: 24)으로 지나치게 복잡하니, 수정하기 전 리팩토링을 고려하거나 수정 범위를 좁히십시오" 같은 고수준 아키텍처 가이드를 내릴 수 있게 된다.
둘째, 코드 분석 앵커의 위험 가중치 부여이다. L1 Grounding Validator가 동작할 때, 복잡도가 유독 높은 파일에서 anchor drift가 발견되면, 단순 경고가 아니라 "장애 유발 가능성이 큰 주요 복잡 지역(Drift in Complexity F symbol)의 stale 상태"로 분류하여 경고 알림의 긴급 수준을 동적으로 관리할 수 있다.
5. 다른 언어의 CC 측정 도구
순환 복잡도는 언어를 가리지 않는 개념이다. 각 생태계마다 표준 도구와 독특한 관습이 있다.
언어 주요 도구 기본 임계값 JavaScript / TypeScript ESLint complexity룰20 Java Checkstyle, PMD, JaCoCo 10 C / C++ Lizard 15 Go gocyclo + gocognit 사용자 지정 C# Visual Studio 코드 메트릭 (내장) — Ruby RuboCop Metrics/CyclomaticComplexity7 PHP PHPMD + PHP_CodeSniffer — 숫자 이면의 차이가 흥미롭다. JavaScript의 ESLint는 기본 임계값이 20으로 가장 높은 편인데,
switch블록 계산 방식 때문이다. 고전적 McCabe CC는case분기 하나당 +1을 더하지만 ESLint는switch전체를 +1로 옵션 설정이 가능하다. 같은 코드라도 도구 설정에 따라 점수가 크게 달라진다.Java의 JaCoCo는 특이하게도 CC를 소스 코드가 아닌 컴파일된 바이트코드에서 추출한다. 코드 생성기나 프레임워크가 자동 생성한 클래스도 측정 대상이 되어, 소스 기반 도구가 놓치는 영역까지 잡아낸다.
C/C++의 Lizard는 빌드 환경이 없어도 동작한다는 점이 핵심이다. C++ 프로젝트는 헤더 파일 의존성과 전처리 지시어가 얽혀 있어 소스를 온전히 파싱하려면 보통 전체 빌드 환경이 필요하다. Lizard는 토크나이저 수준에서 분기 노드만 카운트하는 방식으로 이 문제를 우회한다. 빌드 없이 20개 이상의 언어를 단일 CLI로 스캔할 수 있어, radon처럼 순수 파이썬 생태계 도구와는 운영 방식이 다르다.
Go는 gocyclo(McCabe CC)와 함께 gocognit(인지 복잡도)이 병행 사용되는 경우가 많다. Go의 관용적 코드는 에러 체크를 위한
if err != nil이 반복적으로 나오고, 조기 반환(early return)이 잦다. 이런 패턴은 McCabe CC를 부풀리지만 실제로 읽기 어렵지는 않다. gocognit은 깊은 중첩과 제어 흐름 중단(break, continue)에 가중치를 두어 Go 코드베이스에서 실제로 위험한 함수를 더 정확히 가려낸다.C#은 언어 벤더(Microsoft)가 IDE에 CC 측정을 직접 내장한 유일한 케이스다. Visual Studio에서 별도 플러그인 없이 솔루션 전체의 CC를 확인할 수 있다. Ruby는 RuboCop 기본 임계값이 7로, 여기서 소개한 도구 중 가장 엄격하다. PHP는 PHPMD(품질 스멜 탐지)와 PHP_CodeSniffer(코딩 표준 위반으로 처리)로 역할이 나뉘는데, CC를 "측정 지표"로 보느냐 "규칙 위반"으로 보느냐는 관점 차이가 도구 설계에 그대로 반영된 결과다.
언어를 막론하고 한 방향의 흐름도 있다. SonarQube는 30개 이상 언어를 단일 플랫폼에서 분석하면서 McCabe CC와 별도로 Cognitive Complexity를 제안했다. 깊은 중첩과 제어 흐름 중단에 가중치를 두는 이 지표는 switch-case처럼 McCabe CC를 과대 계산하는 구조물엔 낮은 점수를 주고, 실제로 독해하기 어려운 코드엔 높은 점수를 준다. CC와 Cognitive Complexity를 동시에 보는 관점이 점차 표준화되는 추세다.
6. 정리
radon은 순환 복잡도 알고리즘을 사용해 파이썬 코드의 객관적 위험 등급을 매겨 준다. 이 지표를
deep-wiki의 구조 정보와 나란히 위키 메타데이터로 등재함으로써, AI 에이전트는 한결 입체적인 위험 분석에 입각한 안전한 코드 분석 및 수정 전략을 짤 수 있다.
이 글은 생성형 AI의 도움을 받아 작성되었습니다. 원본 자료를 기반으로 AI가 초안을 생성하고, 작성자가 검토·편집하였습니다.
'IT' 카테고리의 다른 글
에이전트의 다섯 가지 본질 — 루프·도구·맥락·정지·신뢰 (0) 2026.06.06 내 코드 위키를 남의 코딩 에이전트가 쓰게 하려면 — SKILL.md 한 장으론 부족하다 (0) 2026.06.05 생성된 위키 문서에서 틀린 줄을 발견했다 — 고치지 말고, 입력을 바꿔라 (0) 2026.06.05 같은 사실도 신뢰 레벨이 다르다 — 코드 위키의 Trust Gradient (0) 2026.06.04 불필요한 껍데기 걸러내기 — vulture를 이용한 데드 코드 탐지 및 지식 정제 (0) 2026.06.04 LSP를 메모리 안으로 — jedi를 통한 초고속 함수 단위 CALLS 그래프 구축 (0) 2026.06.03 tree-sitter Stage A — 어려웠던 건 빠른 파싱이 아니라 캐시 무효화였다 (0) 2026.06.03 repo마다 5종 자동 페이지 — 단촐한 위키를 결정적으로 채우기 (0) 2026.06.03 repo마다 신뢰도가 다르다 — 4-tier 분류와 2-layer egress allowlist (0) 2026.06.02 기존 pre-push 훅을 깨뜨리지 않고 끼워 넣기 — chain mode와 fail-soft 정책 (0) 2026.06.02