Blog from October, 2017

SonarQube 6.6 in screenshots

이 글은 https://www.sonarsource.com/resources/product-news/news.html#2017-10-13-sonarqube-66-released 를 번역한 글입니다.


SonarSource 팀은 SonarQube 6.6 릴리즈를 알려드리게 되어 자랑스럽게 생각합니다. SonarQuve 6.6 버전은 사용성 및 관리 영역의 많은 기능이 변경되었습니다.


더욱 강력해진 Measure 페이지

Measure 페이지를 완전히 개선하여 시각화 요소를 추가하고 사용성을 개선했습니다. 모든 메트릭은 도메인별로 구분되어 리스트 왼쪽에 함께 표시됩니다:


우측에는 이미 익숙한 List, Tree 및 Treemap 뷰를 표시하고, overview 차트도 함께 표시합니다. Project Overview 차트는 프로젝트 전반에 걸친 리스크 요소를 표시합니다:

주요한 다섯개의 도메인에도 Overview 차트를 적용하였습니다. 예를 들어 신뢰성(Reliability) Overvicew 차트는 아래와 같이 표시됩니다:

다음은 커버리지(Coverage) Overview 입니다:

또한 키보드의 내비케이션 키(화살표 키)를 사용해 도메인에 표시된 파일 리스트를 이동하거나, 파일 상세 뷰를 이동하며 확인할 수 있습니다.

품질 프로파일의 "변경(Edit)" 권한 부여 기능

오랫동안 기다리셨던 기능인 추가되었습니다. 개인 사용자 속은 그룹에게 품질 프로파일(Quality Profile) 수정 권한을 부여할 수 있습니다.

이제 꼭 필요한 사람들에게만 권한을 부여함으로써, 최소한의 권한 부여라는 원칙(the princiape of least privilege)을 쉽게 지킬 수 있습니다.

글로벌 Project Management 필터링 기능

글로벌 레벨의 Project Manage 페이지에서 제공하는 새로운 두가지 검색 기능을 사용해, 프로젝트를 보다 쉽게 관리할 수 있습니다:

"Last analysis before" 옵션을 사용해 SonarQube  인스턴스에서 특정한 기간 동안 분석을 수행하지 않은 프로젝트를 확인할 수 있습니다. 또한 "Only prvisioned" 옵션을 사용해 분석을 한 번도 수행하지 않은 프로젝트를 확인할 수도 있습니다.

실패한 Background Tasks에 대한 알림 기능

"보다 손쉬운 관리"의 관점에서, 실패한 백그라운드 태스크의 상태를 좀 더 편하게 확인할 수 있게 되었습니다. 가장 먼저 프로젝트 폼헤이지에 분석 완료 대기 상태를 표시했습니다. 이전 버전까지 조그맣게 표시되던 내용을 프로젝트 상단 바에 표시되도록 변경하여 가시성을 향상하였습니다:

또한 글로벌 및 프로젝트 레벨에서 알림 메일 발송을 설정할 수 있습니다:

 

Webhook을 통한 인증 지원 기능

마지막으로 webhook URL을 통한 기본 인증 기능을 추가하였습니다:

여기까지입니다 (smile)

자 이제 새로운 버전을 다운로드 하고 사용해 보시기 바랍니다. 설치 전, SonarQube 설치 및 업그레이드 가이드를 읽는 것도 잊지 마시기 바랍니다.


SonarQube 한국어 플러그인 1.5.1이 릴리즈 되었습니다!! 짝짝짝!!


근 1년여 만의 플러그인 업데이트인데요.

  • SonarQube 6.5 기준의 문자열 번역 추가
  • 기존 번역의 어색한 부분 수정

등이 주요한 내용입니다. 로컬라이제이션은 끝이 없네요 ㅠ


Administration > System > Update Center에서 따끈따끈한 플러그인을 받아보실 수 있습니다 ^^*

즐거운 금요일 되세요~ ^^*



>  이 글은 Cognitive Complexity, Because Testability != Understandability 를 번역한 글입니다.


토마스 J. 맥케이브(Thomas J. McCabe)는 1976년 순환 복잡도Cyclomatic Complexity\라는 메트릭을 소개했습니다. 이 메트릭은 프로그래머들에게 "테스트 가능하고, 유지보수 가능한testable and maintainable 코드를 작성하는 가이드로 활용되었습니다. SonarSource의 멤버들은 순환 메트릭이 테스트 가능성testability을 확인하는 데는 매우 유용하지만, 유지보수성을 측정하는 데는 그렇지 않다고 생각했습니다. 그래서 우리는 새로운 인지 복잡도Cognitive Complexity라는 메트릭을 소개합니다. 이 메트릭은 현 시점 이후의 언어 분석 엔진들에 적용됩니다. 이 메트릭을 활용해 여러분은 프로그램의 제어 흐름을 상대적으로 얼마나 잘 이해할 수 있는지 알 수 있습니다.

순환 복잡도는 유지보수성을 측정하지 않습니다.

다음 메소드를 보면서 이야기를 시작하겠습니다:

int sumOfPrimes(int max) {              // +1
  int total = 0;
  OUT: for (int i = 1; i <= max; ++i) { // +1
    for (int j = 2; j < i; ++j) {       // +1
      if (i % j == 0) {                 // +1
        continue OUT;
      }
    }
    total += i;
  }
  return total;
}                  // Cyclomatic Complexity 4
String getWords(int number) {   // +1
    switch (number) {
      case 1:                   // +1
        return "one";
      case 2:                   // +1
        return "a couple";
      default:                  // +1
        return "lots";
    }
  }        // Cyclomatic Complexity 4

이 두 메소드의 순환 복잡도는 동일하지만, 유지보수성이 동일하지는 않습니다. 물론 이 비교가 완전히 공평하지 않을 수 있으며, 맥케이브 본인 역시 그의 논문에서 swtich 구문과 case 구문의 처리가 동일하지 않을 수 있음을 명시하고 있습니다:

이 제한(메소드 당 10)이 불합리하게 보이는 유일한 경우는, 많은 수의 독립 케이스들이 선택 함수(큰 case 구문)의 뒤를 따르는 경우입니다...

달리 말하자면 이러한 점이 바로 순환 복잡도의 맹점입니다. 순환 복잡도 지표는 분명 해당 메소드를 커버하기 위해 필요한 테스트 케이스의 숫자를 알려줄 수는 있지만, 유지 보수성 관점에서 볼때는 항상 옳지는 않습니다. 또한, 아무리 단순한 메소드인 경우에도 순환 복잡도 값은 1이 되며, 거대한 하나의 도메인 클래스의 순환 복잡도 값과 매우 작고 복잡한 클래스의 순환 복잡도 값이 동일할 수도 있습니다. 그어플리케이션 레벨에서 이루어진 여러가지 연구 결과 순환 복잡도는 코드 라인수와 연관되어 있기 때문에, 실제로 새로운 개념을 나타내는 것이 아님이 알려져 있습니다.

그래서 인지 복잡도를 사용합니다!

그래서 우리는 인지 복잡도를 도입했습니다. 인지 복잡도는 메소드의 제어 흐름이 얼마나 이해하기 어려운지, 다시 말해 유지 보수가 얼마나 어려운지를 나타냅니다.

이후 구체적인 예를 들겠습니다만, 우선 인지 복잡도를 도입한 동기에 대해 말씀드리고자 합니다. 가장 큰 이유는 당연히 직관적으로 "공정한" 유지 보수성을 표시하는 것입니다. 그 과정에서 우리가 지표로 무엇인가를 나타낸다면, 사용자가 그 지표를 개선해나가야 한다는 점도 분명하게 알려야 합니다. 때문에 우리는 인지 복잡도를 매우 정교하게 설계해야 했고, 이해를 위해 추가적인 노력을 요구한 코드 구조를 발견하면 복잡도 값을 증가시키고, 읽기 쉽게 짜여진 코드 구조의 경우 복잡도 값을 증가시키지 않으면서 코딩 프랙티스를 다듬어야 했습니다.

기본 기준

아래와 같이 세 가지의 기본 원칙을 수립했습니다:

  • 코드의 순차적인 흐름을 끊는 요소break가 존재하는 경우, 인지 복잡도 값을 증가시킵니다.
  • 코드의 흐름을 끊는 요소가 중첩nested된 경우, 인지 복잡도 값을 증가시킵니다.
  • 복수의 코드 라인을 하나의 코드라인으로 작성했으나, 이해할 수 있을 정도로 합쳐진 코드 구조shorthand structure의 경우, 인지 복잡도 값을 증가시키지 않습니다.

코드 예제

위의 세 가지 기준에 따라 첫 번째 두 메소드를 다시 살펴보겠습니다:

                              // Cyclomatic Complexity    Cognitive Complexity
String getWords(int number) { //          +1
  switch (number) {           //                                  +1
    case 1:                   //          +1
      return "one";
    case 2:                   //          +1
      return "a couple";
    default:                  //          +1
      return "lots";
  }
}                             //          =4                      =1

앞서 이야기했듯, 순환 복잡도의 가장 큰 맹점은 switch 구문의 처리에 있습니다. 인지 복잡도는 순환 복잡도와는 대조적으로 switch 구조를 만난 경우에만 복잡도 값을 증가시키며, case 구문을 만난 경우에는 복잡도 값을 증가시키지 않습니다. 간단히 이야기하자면, switch 구문은 이해하기 매우 쉽기 때문입니다. 즉, 인지 복잡도는 논리 흐름을 얼마나 이해하기 어려운지를 표시합니다.

마찬가지로, 인지 복잡도는 다른 제어 흐름 구조(for, while, do while), 삼항 연산, if/#if/#ifdef/..., else if/elsif/elif/...else 등에 대해서도 case 구분과 같은 방법으로 측정됩니다. 추가적으로 특정 위치로 점프하는 경우(goto, break 및 continue)와 제어 흐름이 중첩되는 경우에는 복잡도를 증가시킵니다:

                                // Cyclomatic Complexity    Cognitive Complexity
int sumOfPrimes(int max) {              // +1
  int total = 0;
  OUT: for (int i = 1; i <= max; ++i) { // +1                       +1
    for (int j = 2; j < i; ++j) {       // +1                       +2 (nesting=1)
      if (i % j == 0) {                 // +1                       +3 (nesting=2)
        continue OUT;                   //                          +1
      }
    }
    total += i;
  }
  return total;
}                               //         =4                       =7

위에서 보듯, 인지 복잡도 값을 기준으로 sumOfPrimes() 메소드가 getWords() 메소드보다 이해하기 어렵다는 것을 알 수 있습니다--제어 흐름의 중첩과 continue 구문에 의한 제어 흐름 이동이 존재하기 때문입니다. 두 메소드의 순환 복잡도 값은 동일한 반면, 인지 복잡도 값은 두 메소드의 이해 가능성에 관한 큰 차이를 보여줍니다.

다음 코드를 보면, 인지 복잡도는 메소드 자체에 대해서는 증가시키지 않음을 알 수 었습니다. 즉, 간단한 도메인 클래스의 인지 복잡도 값은 0이 됩니다:

                              // Cyclomatic Complexity       Cognitive Complexity
public class Fruit {

  private String name;

  public Fruit(String name) { //        +1                          +0
    this.name = name;
  }

  public void setName(String name) { // +1                          +0
    this.name = name;
  }

  public String getName() {   //        +1                          +0
    return this.name;
  }
}                             //        =3                          =0

이를 통해 클래스 레벨 메트릭의 의미가 보다 분명해 집니다. 클래스 목록과 해당 클래스의 인지 복잡도 값을 참조해, 인지 복잡도 값이 높은 경우, 해당 클래스에 메소드가 많이 존재한다는 의미가 아니라 클래스의 로직이 많다는 것을 알 수 있습니다.

인지 복잡도를 사용해 보십시오

이제 인지 복잡도를 활용하기 위해 어떤 준비가 필요한지 대부분 아셨을 것입니다. 불리언 연사자 카운트 방법에는 다소 차이가 있으므로, 자세한 내용은 링크의 화이트 페이퍼를 읽어보시기 바랍니다. 인지 복잡도를 도입하고자 하는 경우, 그 도입시기에 관해 궁금하실 수 있을 것 같습니다.

우리는 우선 순환 복잡도와 마찬가지로 메소드 레벨에서 인지 복잡도 규칙을 각 언어에 적용할 것입니다. 주요 언어(Java, JavaScript, C#, C/C++/Objective-C)에 적용을 우선 시작합니다. 동시에 현재 메소드 단위의 "Cyclomatic Complexity" 규칙을 순수한 순환 복잡도 메트릭을 수정할 것입니다(현재 해당 규칙은 Cyclomatic 및 Essential 복잡도의 조합으로 구현되어 있습니다).

결과적으로 클래스 및 파일 레벨의 인지 복잡도 규칙과 메트릭을 추가할 예정입니다. 이제 한 걸음을 내딛었을 뿐입니다.


-----


인지 복자도는 SonarQube v6.5 및 최신 언어 플러그인을 기준으로 아래와 같이 적용되어 있습니다 (smile) 기존의 Complexity 메트릭과 함께 Cognitive Complexity 메트릭도 적용되어 있으므로, 활용해 보시면 좋을 것 같습니다 ^^