# 순환 복잡도: 숫자 너머의 진실

URL: https://codebasechat.com/ko/journal/cyclomatic-complexity-korean
Type: blog
Locale: ko
Published: 2026-07-21
Updated: 2026-07-21

---

> 순환 복잡도는 함수를 통과하는 독립적인 경로의 수를 센다. 숫자는 중요하지만, 팀이 그 숫자를 잘못 사용하기 쉽다. 올바른 threshold, 인지 복잡도, 그리고 온보딩 시간과의 관계를 알아보자.

순환 복잡도는 함수를 통과하는 독립적인 경로의 개수를 센다. 분기가 없는 함수는 1을 받는다. `if`를 하나 추가하면 2가 된다. 4가지 케이스를 가진 `switch`를 추가하면 6으로 뛴다. 이 숫자는 모든 경로를 테스트하기 위해 필요한 테스트 케이스의 개수를 알려주고, 낯선 사람이 그 함수를 머리에 담고 있는 데 걸리는 시간과 상관관계가 있다.

그것이 이 메트릭의 전부다. 중요한 것은 팀이 이것을 어떻게 사용하는가이고, 어디서 실수하는가이다.

## 순환 복잡도가 실제로 세는 것

McCabe는 1976년에 그래프 이론 용어로 간선 개수에서 노드 개수를 뺀 후 2를 더하는 것으로 정의했다. 실제로는 그래프 이론이 필요 없다. 결정 지점을 센다: `if`, `else if`, `case`, `while`, `for`, `catch`, `&&`, `||`, 삼항 연산자. 1을 더한다. 그것이 점수다.

`def price(order):
    if order.is_vip:            # +1
        if order.total > 100:   # +1
            return order.total * 0.8
        return order.total * 0.9
    elif order.has_coupon:      # +1
        return order.total * 0.95
    return order.total`이것은 4를 받는다. 높지 않다. 하지만 이미 "할인을 적용한다"로 시작한 함수에 3단계의 분기가 있다. 이것이 주목할 가치가 있는 패턴다: 복잡도는 한 번에 하나씩 `elif`로 늘어나고, 아무도 악당이 아니다.

## "10" Threshold는 어디서 나왔는가 (그리고 도구마다 왜 다른가)

모두가 인용하는 숫자는 10이다. 이것은 NIST 특별 간행물 500-235에서 나왔고, McCabe와 Watson은 10 이상의 한계는 경험이 풍부한 직원, 공식적인 설계, 그리고 포괄적인 테스트 계획을 가진 팀을 위해 예약되어야 한다고 썼다. 즉, 10은 기본값이지 법칙이 아니다.

도구는 선을 어디에 그을지에 대해 동의하지 않으며, 이것은 gate를 구성하기 전에 알 가치가 있다:

- 
**NIST SP 500-235**: 10

- 
**ESLint `complexity` rule**: 20

- 
**Microsoft CA1502**: 25

- 
**Steve McConnell, *Code Complete***: 0-5 괜찮음, 6-10 주의, 10+ 리팩터

- 
**Carnegie Mellon 참고 범위**: 1-10 단순, 11-20 테스트하기 어려움, 20+ 이해하기 어려움, 50+ 유지보수 불가능

4개의 출처, 4개의 숫자. CI gate가 10에서 실패하고 팀원의 프로젝트가 25에서 gate한다면, 누구도 틀린 것이 아니다. 당신은 단지 다른 위험 허용도를 측정하고 있을 뿐이다. Microsoft의 NIST 추론이 설명된 [공식 문서](https://learn.microsoft.com/en-us/visualstudio/code-quality/code-metrics-cyclomatic-complexity?view=visualstudio)를 읽으면 요약 대신 소스를 알 수 있다.

우리가 실제로 설정할 것은 무엇인가: 새 코드의 경고선으로 10-15, PR이 두 번째 검토를 받는 지점으로 20, 하드 스탑으로 50. 10 이하에서는 리뷰 시간을 이 문제로 낭비하지 말자.

## 함정: 좋은 점수는 읽기 쉬운 함수를 의미하지 않는다

팀이 여기서 문제를 만난다. 함수는 6을 받고도 읽기 정말 어렵고, 함수는 14를 받고도 단순할 수 있다.

10개의 케이스가 있고 각각 상수를 반환하는 평면 `switch`를 생각해보자. 이것은 복잡도 10을 받고, 대부분의 엔지니어는 15초 만에 읽는다. 왜냐하면 패턴이 명확하기 때문이다: 하나가 들어가고, 하나가 나가고, 분기 사이에 상태가 유지되지 않는다. 이제 3개의 중첩된 `if` 블록과 공유 변수를 변경하는 루프가 있는 함수를 생각해보자. 이것은 6을 받을 수 있고, 시니어 엔지니어가 추적하는 데 5분이 걸릴 것이다. 왜냐하면 어떤 분기에 실제로 있는지 알기 위해 전체 호출 스택을 머리에 담고 있어야 하기 때문이다.

순환 복잡도는 경로를 측정한다. 중첩 깊이, 변수 범위, 또는 조건과 그 효과가 파일에서 얼마나 멀리 떨어져 있는지는 측정하지 않는다. 같은 점수를 받은 두 함수는 완전히 다른 읽기 경험이 될 수 있다.

우리는 "10 미만"을 "검토 가능"의 대리로 취급하고, 린터가 초록불이라는 이유로 PR을 통과시키고, 3주 후에 주니어 엔지니어가 같은 함수 안에서 오후를 잃는 팀을 봤다. 점수는 통과했다. 읽기가 더 쉬워지지 않았다.

## 순환 복잡도 vs. 인지 복잡도: 두 가지 다른 질문

SonarSource는 2017년에 인지 복잡도를 도입했고, 정확히 이 차이를 해결하기 위해 도입했다. 순환 복잡도는 "이 함수가 몇 개의 경로를 가지는가"에 답한다. 인지 복잡도는 "이 함수를 머리에 담기가 얼마나 어려운가"에 답하고, 평면 구조보다 중첩에 더 페널티를 준다.

`switch` 문은 인지 점수를 거의 움직이지 않는다. 루프 안의 3단계 깊이 `if`는 빠르게 움직인다. 왜냐하면 중첩의 각 추가 수준은 그 전의 정신적 비용을 복합적으로 증가시키기 때문이다. SonarSource의 [공식 설명](https://www.sonarsource.com/resources/cognitive-complexity/)은 당신이 직접 구현하고 싶다면 점수 규칙을 설명하고, 순환 복잡도를 지원하는 대부분의 린터는 이제 인지 복잡도를 두 번째 별도 규칙으로 지원한다.

팀이 코드를 작성하지 않은 사람이 2명 이하라면 인지 복잡도를 건너뛰어도 된다. 리뷰하는 모두가 복잡한 함수가 어디에 있는지 이미 알고 있다면. 그 순간부터 켜라. 왜냐하면 그것이 정확히 그것이 해결하도록 설계된 차이이기 때문이다.

![Red string connecting index cards in a branching decision-tree pattern on a cork board](https://fdzlnqpwsaniezitwiuw.supabase.co/storage/v1/object/public/cms-media/codebasechat/2026-07/c5bc79-inline1.webp)

## AI 코드 리뷰 도구가 이 숫자로 하는 것 (그리고 놓치는 것)

GitHub Copilot의 코드 리뷰, CodeRabbit, Qodo, Greptile 모두 어느 정도 PR에 복잡도 신호를 표시한다. 일부는 threshold를 넘은 함수에 플래그를 지정한다. 일부는 "이 PR이 3개 파일의 복잡도를 증가시킨다"고 요약한다. 거의 없는 것은 6개월 후에 맥락 없이 파일을 열 사람에게 *왜* 그것이 중요한지 알려주는 것이다.

그것이 실제 차이다. PR에 대한 복잡도 경고는 주석의 숫자다. 그것은 리뷰어에게 추가된 분기가 그곳에 속하는지, 3개 파일에 걸쳐 논리를 복제하는지, 또는 올바른 수정이 guard 절인지 전체 추출 메서드 통과인지를 알려주지 않는다. AI 도구는 세는 것이 좋다. 메스의 모양을 설명하는 것은 아직 좋지 않다.

실제로 그 차이를 닫는 것은 숫자를 사람이 여전히 답해야 하는 질문과 쌍을 이루는 것이다: 이 함수가 한 가지를 하는가, 아니면 `if` 문에 싸인 세 가지를 하는가? 린터는 당신을 위해 그것에 답하지 않는다. 단지 당신이 어디를 봐야 하는지 알려줄 뿐이다.

## 이것이 사이드 프로젝트보다 100K-LOC 저장소에서 더 중요한 이유

혼자 작성한 코드베이스에서는, 복잡도는 당신이 이미 해결한 메모리 문제다. 10개의 복잡한 함수를 이름으로 알고, 왜 그들이 복잡한지 알고, 생각 없이 그들 주위를 우회한다. 이것은 이 청중의 대부분이 있는 상황이 아니다.

5명에서 50명의 엔지니어가 있는 공유 저장소에서는, 아무도 전체 지도를 보유하지 않는다. 22를 받는 함수는 원래 저자가 완벽하게 이해했지만, 6개월 후에는 다른 엔지니어가 처음부터 재구성해야 하는 함수가 된다. 보통 마감 기한 아래에서. 당신은 이미 이것을 했다: 함수 이름으로 grep, 파일을 통해 Ctrl+F, 의심스러운 라인들에 git blame, 그 다음 8개월 전에 팀을 떠난 누군가에게 메시지를 보낸다.

이것은 또한 복잡도가 검색과 상호작용하기 시작하는 곳이다. 높은 복잡도 함수는 올바르게 요약하기가 더 어려우며, 이는 팀원이나 코드 검색 도구가 한 문장에서 정확하게 설명하기가 더 어렵다는 의미다. "이 함수가 무엇을 하는가"를 복잡도-4 함수에 대해 묻고 깔끔한 답을 얻는다. 같은 질문을 4개의 중첩된 분기와 복잡도-22 함수에 대해 묻으면 정직한 답은 "어떤 경로를 물어보느냐에 따라 다르다"이다. 그 모호성은 정확히 1일 차에 새 입사자를 느리게 하는 것이고, 이것이 저장소 수준에서 PR당 린트 경고로만 아니라 복잡도를 추적할 가치가 있는 이유다.

## 아무도 메트릭에 포함하지 않는 실제 비용: 온보딩 시간

여기가 대시보드에 나타나지 않는 부분이다. 팀에 새로 참여한 주니어 엔지니어는 "순환 복잡도 23"을 경험하지 않는다. 그들이 경험하는 것은: 이 파일을 열었는데, 어떤 분기가 언제 실행되는지 모르겠고, 40분을 읽었다.

우리는 몇 가지 온보딩 사이클에 걸쳐 이것을 느슨하게 측정했다: 복잡도 점수가 15를 초과하는 함수는 새 입사자들이 워크스루에서 올바르게 설명하는 데 복잡도 점수가 8 이하인 함수보다 대략 3-4배 더 오래 걸렸다. 높은 복잡도 함수가 더 많이 했기 때문이 아니라, 어떤 분기가 어떤 조건 아래에서 실행되는지 추적하는 것이 실제의, 순차적인 읽기 시간을 걸리고, 아무도 중첩된 조건을 첫 번째 통과에서 올바르게 스캔하지 않기 때문이다.

이것이 자주 온보딩하는 팀에서 메트릭이 이득을 취하는 곳이다. 이것은 실제로 코드 품질 숫자가 아니다. 이것은 "그것을 작성하지 않은 다음 사람에게 이것이 얼마나 많은 시간이 걸릴 것인가"의 대리다. 그것을 그런 식으로 추적하고 threshold 대화는 훨씬 덜 추상적이 된다.

![Senior engineer pointing at a laptop screen while a junior engineer takes notes during a pairing session](https://fdzlnqpwsaniezitwiuw.supabase.co/storage/v1/object/public/cms-media/codebasechat/2026-07/7c91aa-inline3.webp)

## 팀을 막지 않고 Gate하는 방법

측정한 후 gate하라. 하나를 선택하라:

- 
**Python**: `radon cc -a -s .`는 모든 함수를 등급문자로 보여준다; `radon cc -n c .`는 C등급 이상으로 필터한다.

- 
**JavaScript / TypeScript**: ESLint의 `complexity` rule. `['warn', { max: 15 }]`로 시작한다.

- 
**Go**: `gocyclo`. 패키지를 가리키면 threshold를 초과하는 모든 함수를 인쇄한다.

- 
**Java / C#**: SonarQube 또는 PMD. 보통 이미 팀이 둘 중 하나를 실행한다면 CI에 연결되어 있다.

집행을 켜기 전에 전체 저장소에 걸쳐 한 번 실행하라. 기준을 얻을 것이고, 아마도 40 이상의 범위에 있는 함수 몇 개를 얻을 것이다. 현재 팀의 누구도 작성하지 않은 함수들이다. 그것들에 대한 빌드를 역으로 막지 마라; 그것은 단지 사람들을 린터를 우회하도록 가르친다.

새 코드를 10-15에서 gate하라. 자동 거부는 아니지만 두 번째 리뷰어 플래그로 20을 넘는 것을 플래그하라; 그들 중 일부, 평면 `switch` 같은, 괜찮다. 50을 넘는 것을 PR에 대한 주석이 아니라 기술 부채 티켓으로 취급하라.

![Hands typing on a mechanical keyboard in front of a blurred pull request review interface with red and green diff bars](https://fdzlnqpwsaniezitwiuw.supabase.co/storage/v1/object/public/cms-media/codebasechat/2026-07/6474ad-inline2.webp)

한계는 도구 체인이 매번 같은 방식으로 적용할 때만 유지된다. 한 번 마감을 위해 포기하는 규칙은 영원히 포기된다.

## 점수를 쫓는가, 아니면 함수를 쫓는가?

10에서 hard gate하고 평면의, 지루한, 읽기 쉬운 함수를 배송하는 팀은 좋은 상태다. 10에서 hard gate하고 함수를 4개의 더 작은 것으로 분할하기 시작하고 그들이 아무도 3개 탭을 열지 않고 추적할 수 없는 체인에서 서로를 호출하는 팀은 숫자를 더 낫게 만들고 코드베이스를 더 나쁘게 만들었다.

순환 복잡도는 소화기, 소화기가 아니다. 그것은 당신에게 어디를 봐야 하는지 알려준다. 그것은 당신이 거기 도착했을 때 무엇을 할지 알려주지 않고, 점수가 목표가 아니라 그것이 대리해야 하는 읽기 용이성을 대신 취급하는 것이 팀이 어떻게 초록 대시보드와 여전히 새 입사자가 3주를 느끼는 저장소를 끝내는지이다.

## FAQ

### 순환 복잡도 10은 절대 규칙인가?

아니다. NIST는 기본값으로 제안했고, ESLint는 20을 기본값으로, Microsoft는 25를 사용한다. 팀이 위험 허용도를 기반으로 고르는 숫자다. 새 코드의 경고선으로 10-15, 두 번째 리뷰 지점으로 20을 권장한다.

### 좋은 복잡도 점수가 좋은 코드를 의미하는가?

아니다. 10의 평면 switch는 읽기 쉽지만, 3단계 중첩 if는 복잡도 6일 수 있고 이해하기 어렵다. 복잡도는 경로를 세고, 중첩 깊이나 변수 범위는 측정하지 않는다.

### 인지 복잡도란 무엇인가?

SonarSource에서 2017년에 도입했으며, 중첩에 더 페널티를 준다. "이 함수를 머리에 담기가 얼마나 어려운가"를 측정한다. 순환 복잡도가 "경로가 몇 개인가"만 측정하는 것과 달리.

### AI 코드 리뷰 도구는 복잡도로 무엇을 하는가?

GitHub Copilot, CodeRabbit, Qodo는 복잡도 증가를 플래그한다. 하지만 대부분은 왜 이것이 중요한지 설명하지 않는다. 그들은 세기는 좋지만, 메스의 모양을 설명하는 것은 아직 좋지 않다.

### 큰 저장소에서 복잡도가 더 중요한 이유는 무엇인가?

작은 팀에서 당신은 복잡한 함수를 알고 있다. 큰 저장소에서, 새 입사자는 고복잡도 함수를 모르고, 그것을 이해하는 데 시간이 3-4배 더 걸린다. 복잡도는 온보딩 비용의 대리다.

### 어떻게 하면 복잡도 점수를 추적하지 않고도 읽기 쉬운 코드를 얻을 수 있는가?

한 가지를 할 함수를 만든다. 3개 파일에 걸쳐 로직을 복제하지 않는다. 분기를 추적하기 위해 전체 호출 스택을 보유할 필요가 없도록 쓴다. 점수는 목표가 아니라 신호일 뿐이다.

### Python에서 복잡도를 측정하려면?

`radon cc -a -s .`로 모든 함수와 그 등급을 본다. `radon cc -n c .`로 C 이상만 본다. 또는 pre-commit hook에서 radon을 실행하여 자동 측정한다.

### 복잡도 threshold에 도달할 때, 함수를 분할하는 것이 항상 맞는가?

아니다. 10개의 케이스를 가진 평면 switch는 복잡도 10이지만 읽기 쉽다. 함수를 분할하면 점수는 낮아지지만 읽기가 더 어려워질 수 있다. 읽기 용이성이 목표다.