동일한 메소드를 여러 번 호출 할 때의 순환 복잡성


12

Code Review 에 대한 질문 덕분에 아래 코드의 Cyclomatic Complexity가 무엇인지에 대해 약간의 의견 차이가 생겼습니다.

public static void main(String[] args) {
    try {
        thro();
        thro();
        thro();
        thro();
        thro();
        thro();
        thro();
    }
    catch (NullPointerException e) {
    }
}

private static Random random = new Random();

public static void thro() throws NullPointerException {
    if (random.nextBoolean())
        throw new NullPointerException();
    System.out.println("No crash this time");
}

이 코드를 Eclipse에서 작성하고 Eclipse 메트릭스 플러그인 을 사용하면 기본 메소드의 McCabe 순환 복잡도가 2이고 2의 thro메소드라는 것을 알 수 있습니다.

그러나 다른 사람이 thro여러 번 호출하는 것이 복잡하다는 것을 말하고 number of calls * method complexity주 메소드의 복잡성이 7 * 2 = 14라고 주장합니다.

우리는 다른 것을 측정하고 있습니까? 우리 둘 다 맞을 수 있습니까? 아니면 여기의 실제 순환 복잡성은 무엇입니까?


5
경로가 두 개뿐이므로 함수 의 CC 는 2입니다. 프로그램 의 CC 가 더 높습니다. 이것은 어둠 속에서 완전한 찌름이지만 코드 분석 소프트웨어는 복잡한 응용 프로그램의 CC를 한 번에 계산할 수 없기 때문에 각 기능을 별도의 블랙 박스로 사용한다고 가정합니다.
Phoshi

@Phoshi 당신이 대답으로 그것을 작성하고 (가능한 경우) 둘이 분리되어 있음을 보여주는 링크를 제공한다면, 나는 그 대답을 기꺼이 받아들입니다.
Simon Forsberg

CC 측정에서 가능한 예외로 인해 발생하는 모든 경로를
세면

답변:


9

내가 이것을 올바르게 이해했을 때, Cyclomatic Complexitymain8은 코드를 통해 선형으로 독립적 인 경로의 수입니다. 7 줄 중 하나에서 예외를 받거나 전혀받지 않지만 결코 1 개를 넘지 않아야합니다. 가능한 "예외 지점"각각은 코드를 통한 하나의 다른 경로에 정확히 해당합니다.

McCabe가이 메트릭을 발명했을 때 예외 처리를 염두에두고 프로그래밍 언어가 없었던 것 같습니다.


그러나 예외를 발생시키는 행은 실제로 중요합니까?
Simon Forsberg

5
@ SimonAndréForsberg : 그렇습니다. "thro"는 호출 될 때 글로벌 카운터를 증가시키는 부작용이 있다고 생각합니다 (코드를 통해 가능한 경로를 변경하지 않음). 이 카운터의 가능한 결과는 0에서 7까지이므로 CC가 8 이상 임을 증명합니다.
Doc Brown

사용중인 메트릭 플러그인 이 메소드에 대해 잘못된 값을 보고한다고 말 하시겠습니까 main?
Simon Forsberg

@ SimonAndréForsberg : 글쎄, 난 당신의 메트릭 플러그인을 모르지만 2는 분명히 8이 아닙니다.
Doc Brown

메트릭에 대한 링크가 .... 내 질문에이 플러그인의
사이먼 포스 버그

6

'다른 사람'이기 때문에 여기에 대답하고 내가 말한 것에 대해 정확해야합니다 (다른 포럼에 대해서는 특히 정확하지 않았습니다).

위의 코드 예제를 사용하여 순환 복잡도를 8로 계산하고 코드에 주석을 달아 계산 방법을 보여줍니다. 내가 통해 성공적인 루프를 고려할 것입니다 경로를 설명하는 데 모든thro() '기본' '코드 경로로 호출'(또는 'CP = 1') :

public static void main(String[] args) {
  try {
             // This is the 'main' Code Path: CP = 1
    thro();  // this has a branch, can succeed CP=1 or throw CP=2
    thro();  // this has a branch, can succeed CP=1 or throw CP=3
    thro();  // this has a branch, can succeed CP=1 or throw CP=4
    thro();  // this has a branch, can succeed CP=1 or throw CP=5
    thro();  // this has a branch, can succeed CP=1 or throw CP=6
    thro();  // this has a branch, can succeed CP=1 or throw CP=7
    thro();  // this has a branch, can succeed CP=1 or throw CP=8
  }
  catch (NullPointerException e) {
  }
}

따라서이 주요 방법에서 8 개의 코드 경로를 셀 수 있습니다.

Java 용어로, 함수를 종료하기위한 각 메커니즘은 그 복잡성으로 계산되므로 성공 상태를 가지고 있으며 최대 3 개의 예외를 발생시키는 메소드에는 4 개의 문서화 된 종료 경로가 있습니다.

이러한 함수를 호출하는 메소드의 복잡성은 다음과 같습니다.

CC(method) = 1 + sum (methodCallComplexity - 1)

다른 생각으로는 고려해야 할 것은 내 의견 catch으로는이 방법이 방법의 복잡성에 영향을 미치지 않으며catch 단순히 throws지점의 대상이므로 여러 throw번의 카운트 대상인 catch 블록이라는 것입니다. throw모든 것에 대해 한 번이 아니라 각각에 대해 .


OutOfMemoryExceptions의 가능한 분기를 계산하고 있습니까? 필자는 의미 적으로 코드 분기를 일으킬 수 있지만 메트릭의 유용성을 희석 할 때 아무도 계산하지 않습니다.
Telastyn

아니, 난 아니에요 ... 그리고 당신 말이 맞지만,이 논쟁의 맥락에서, 나는 메소드가 던지기로 선언 된 예외 만 계산합니다. 또한 메소드가 세 가지 예외를 선언하지만 콜린 치 코드가 catch (Throwable t) {...예외를 처리하면 선언하는 예외 수는 중요하지 않습니다.
rolfl
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.