Learn

[소프트웨어 공학] 순환 복잡도(Cyclomatic Complexity) 완벽 해부: 내 코드는 얼마나 복잡할까?

SangPedia 2026. 3. 1. 00:03
반응형

[소프트웨어 공학] 순환 복잡도(Cyclomatic Complexity) 완벽 해부: 내 코드는 얼마나 복잡할까?

소프트웨어 개발이나 IT 인프라 연동(SSO, SAML/OIDC 등) 스크립트를 작성하다 보면, 코드가 점점 길어지고 읽기 힘들어지는 경험을 해보셨을 겁니다. "코드가 복잡하다"는 느낌을 객관적인 '숫자'로 표현할 수 있을까요?

1976년 토마스 맥케이브(Thomas McCabe)가 고안한 순환 복잡도(Cyclomatic Complexity)는 바로 이 질문에 대한 수학적이고 논리적인 해답입니다. 오늘은 이 순환 복잡도의 본질부터 계산법, 그리고 실무 적용 가이드까지 체계적으로 해부해 보겠습니다.

1. 문제의 본질 및 논리적 모델링 (Problem Definition)

순환 복잡도의 핵심 목표는 "코드 내에 독립적으로 실행되는 경로(Path)가 총 몇 개인가?"를 정량적으로 측정하는 것입니다.

  • 수학적 기초 (Graph Theory): 프로그램의 제어 흐름을 '제어 흐름 그래프(Control Flow Graph, CFG)'로 변환하여 분석합니다.

    • 노드(Node): 순차적으로 실행되는 명령문 블록

    • 엣지(Edge): 노드에서 노드로 이동하는 제어 흐름 (화살표)

  • 숨은 핵심 변수: 코드의 단순한 길이(Line of Code, LOC)가 아니라, if, for, while, switch 와 같은 분기점(Decision Point)의 개수가 복잡도를 결정하는 절대적인 변수입니다.

2. 단계별 구조화 및 계산법 (Decomposition)

순환 복잡도 $V(G)$를 계산하는 방법은 크게 3가지 접근법이 있습니다. 실무에서는 두 번째(분기점 기준) 방식이 가장 직관적으로 사용됩니다.

[방법 A] 그래프 이론 기반 (공식)

$$V(G) = E - N + 2P$$

  • E (Edges): 그래프의 화살표 개수

  • N (Nodes): 그래프의 노드 개수

  • P (Connected Components): 연결된 컴포넌트 수 (일반적인 단일 프로그램/함수에서는 1)

[방법 B] 분기점 기준 (가장 쉬운 실무 공식)

$$V(G) = (\text{분기문의 개수}) + 1$$

  • 코드 내에 존재하는 조건문(if, while, for, case 등)의 총개수에 1을 더하면 됩니다.

[방법 C] 폐쇄 영역 기준

  • 제어 흐름 그래프를 그렸을 때, 선으로 완전히 둘러싸인 면(Region)의 개수 + 1(외부 영역)을 계산합니다.

💡 IT 엔지니어 실무 팁: AD FS Custom Rule이나 SAML 연동 시 작성하는 조건부 클레임 규칙(Claim Rules) 역시 분기(=>, NOT EXISTS 등)가 많아질수록 순환 복잡도가 급증하여 유지보수 장애 지점이 될 수 있습니다.

3. 직관적 이해: 전문가 vs 중학생 수준 해설

독자분들의 빠른 이해를 돕기 위해, 이 개념을 두 가지 시각에서 요약했습니다.

구분 🎓 전문가 수준 (심화 분석) 🏫 중학생 수준 (단순 해설)
정의 제어 흐름 그래프 상의 선형 독립 경로의 총수 코드에서 '선택의 갈림길'이 얼마나 많은지 나타내는 점수
목적 Basepath Testing의 상한선 결정 및 리팩토링 지표 코드가 얼마나 '꼬여 있는지' 확인하고 쉽게 풀기 위해
해석 $V(G)$는 단위 테스트 시 커버리지를 100% 달성하기 위한 최소 테스트 케이스 수와 일치함 이 숫자가 크면 '경우의 수가 너무 많아 풀기 힘든 미로'와 같음

4. 실무 활용 가이드 및 대안 검토

내 코드의 순환 복잡도를 측정했다면, 이 수치를 어떻게 해석하고 대응해야 할까요?

🚨 복잡도 점수별 위험도 판정 기준

순환 복잡도 V(G) 위험 수준 의미 및 권고 사항 (Action Plan)
1 - 10 낮음 (안정) 매우 구조적이고 안정적인 코드. 단위 테스트 작성이 용이함.
11 - 20 보통 (주의) 복잡도가 서서히 증가하는 단계. 메서드 분리 등 부분적인 리팩토링 고려 필요.
21 - 40 높음 (위험) 로직이 지나치게 얽혀 있어 버그 발생 확률이 높음. 전면적인 리팩토링 권장.
50 이상 재앙 (테스트 불가) 코드를 이해하고 유지보수하기 거의 불가능함. 즉시 모듈 분할 및 재작성 필수.

🔍 한계점과 대안 (Cognitive Complexity)

순환 복잡도에도 한계는 있습니다. 단순히 switch-case 문이 10개 나열된 코드(복잡도 11)는 사실 읽기 쉬운 반면, 이중 삼중으로 중첩된 if 문(복잡도 4)은 인간이 이해하기 훨씬 어렵습니다.

따라서 최근에는 개발자가 코드를 읽을 때 느끼는 심리적 부담을 측정한 인지 복잡도(Cognitive Complexity)를 함께 교차 검증하는 추세입니다.

5. 결론 및 참고 문서

순환 복잡도는 완벽한 소프트웨어를 보장하는 마법의 지팡이는 아니지만, "내 코드가 테스트 가능한 상태인가?"를 묻는 가장 객관적인 척도입니다. SSO 연동이나 복잡한 인프라 자동화 스크립트를 짤 때, 조건문을 추가하기 전 이 수치를 한 번쯤 떠올려 보시길 바랍니다.

🔗 공식 참고 문서 가이드:

도움이 되셨나요? 여러분이 다루시는 스크립트 중 가장 복잡했던 로직은 무엇이었는지 댓글로 남겨주세요!

반응형