Halstead Complexity

Halstead 복잡도는 1977년 Maurice Howard Halstead가 제안한 소프트웨어 메트릭으로, 프로그램의 복잡성을 연산자(operators)와 피연산자(operands)의 수를 기반으로 측정한다.
이는 프로그램의 구현 난이도와 이해도를 정량적으로 평가하는 방법을 제공한다.
코드의 구현을 반영하지만 특정 플랫폼에서의 실행과는 독립적이다.

기본 측정 요소:
프로그램의 기본 요소는 다음과 같이 정의된다:

  • n1: 고유 연산자의 수
  • n2: 고유 피연산자의 수
  • N1: 총 연산자의 출현 횟수
  • N2: 총 피연산자의 출현 횟수
    예를 들어, 다음 코드를 살펴보자.
1
sum = a + b * 2;

이 코드에서:

  • 연산자: =, +, * (n1 = 3)
  • 피연산자: sum, a, b, 2 (n2 = 4)
  • 총 연산자 출현: =, +, * (N1 = 3)
  • 총 피연산자 출현: sum, a, b, 2 (N2 = 4)

Halstead 메트릭의 주요 측정항목

  1. 프로그램 길이(Program Length):
    N = N1 + N2
    이는 프로그램에서 사용된 모든 연산자와 피연산자의 총 출현 횟수.
  2. 프로그램 어휘(Program Vocabulary):
    n = n1 + n2
    이는 프로그램에서 사용된 고유한 연산자와 피연산자의 총 개수.
  3. 프로그램 볼륨(Program Volume):
    V = N * log2(n)
    이는 프로그램의 정보 내용을 비트 단위로 표현한 것.
  4. 난이도(Difficulty):
    D = (n1/2) * (N2/n2)
    이는 프로그램을 이해하고 유지보수하는 난이도를 나타낸다.
  5. 노력(Effort):
    E = D * V
    프로그램을 구현하거나 이해하는 데 필요한 정신적 노력을 나타낸다.
  6. 구현 시간(Implementation Time):
    T = E / 18
    프로그램을 구현하는 데 필요한 시간을 초 단위로 추정한다.

실제 적용 예시:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// 원래 코드
public int calculateTotal(int[] numbers) {
    int sum = 0;
    for (int i = 0; i < numbers.length; i++) {
        sum = sum + numbers[i];
    }
    return sum;
}

// 개선된 코드
public int calculateTotal(int[] numbers) {
    return Arrays.stream(numbers).sum();
}

두 번째 버전은 첫 번째 버전보다 Halstead 복잡도가 낮다. 연산자와 피연산자의 수가 줄어들었기 때문이다.

측정 도구

  1. PMD: Java 코드의 Halstead 메트릭 측정
  2. SonarQube: 다양한 언어의 코드 품질 분석
  3. Understand: 상세한 코드 메트릭 분석 도구
  4. CCCC: C++용 코드 복잡도 분석 도구

전략 및 권장사항

  1. 코드 로직 단순화: 복잡한 조건문을 간소화하고 명확한 로직 구조를 사용한다.
  2. 고유 연산자와 피연산자 사용 줄이기: 코드의 일관성을 높이고 복잡성을 낮춘다.
  3. 코드 리팩토링: 큰 함수를 작은 단위로 분할하여 복잡도를 낮춘다.
  4. 높은 수준의 추상화 사용: 디자인 패턴이나 프레임워크를 활용하여 복잡한 로직을 추상화한다.

주의사항

  1. Halstead 복잡도만으로는 코드의 전체적인 품질을 평가하기 어려우므로, 다른 메트릭들과 함께 사용해야 한다.
  2. Halstead 메트릭은 프로그램의 구문적 특성만을 측정하며, 의미적 복잡성은 고려하지 않는다.
  3. 언어와 컨텍스트에 따라 “좋은” 점수의 기준이 다를 수 있으므로, 프로젝트 특성에 맞는 벤치마크를 설정해야 한다.

참고 및 출처