SonarQube로 코드 품질 개선하기 결과 분석 & 리팩토링 (SonarScanner CLI)

양말고양이·2025년 2월 18일

프로젝트 이슈 🐟

목록 보기
7/7

혼자만의 지식으로 클린 코드를 작성하는 데 어려움을 느껴 정적 코드 품질 분석 도구인 SonarQube의 도움을 받아보려고 합니다.

이번에는 프로젝트 소스코드를 바탕으로 간단하게 결과 보고서를 받고, 결과를 바탕으로 리팩토링해보겠습니다.




1. SonarScanner CLI 실행 & 트러블 슈팅

이번에는 로컬 환경에서 빠르게 테스트를 진행해 볼 것이기 때문에, Docker image를 통해 SonarScanner CLI를 다운받아 사용할 것입니다.

SonarQube 설치 과정은 공식 문서도 잘 되어 있고 레퍼런스도 많기 때문에 생략하겠습니다.
저는 간단하고 익숙한 Docker를 활용해 설치했습니다.


공식 문서를 보면 아래의 명령어를 입력하는 간단한 방법으로 테스트할 수 있음을 알 수 있습니다.


# 공식문서 명령어

docker run \
    --rm \
    -e SONAR_HOST_URL="http://${SONARQUBE_URL}"  \
    -e SONAR_TOKEN="myAuthenticationToken" \
    -v "${YOUR_REPO}:/usr/src" \
    sonarsource/sonar-scanner-cli

SONAR_HOST_URL

주의할 점은 localhost 대신 host.docker.internal을 사용해야한다는 것입니다.

도커 컨테이너 내부에서의 localhost는 컨테이너 자신을 가리키기 때문에, 컨테이너를 실행한 호스트 머신을 가리키려면 host.docker.internal을 사용해야 합니다.

그렇지 않으면 Failed to connect to /localhost:9000 에러를 만나게 됩니다.

따라서 SonarQube를 실행한 포트 번호와 함께 host.docker.internal:9000로 설정해줬습니다.


SONAR_TOKEN

아래와 같이 Administration > Security > Users에서 새로 토큰을 만들어 복사했습니다.


${YOUR_REPO}

분석할 코드가 있는 프로젝트 디렉토리로 이동해서 실행할 것이기 때문에,$(pwd)로 바꿔줬습니다.




-Dsonar 추가 설정

projectKey

이대로 실행하면 아래처럼 필수 속성을 정의하라는 에러 메시지가 나옵니다.


You must define the following mandatory properties for 'Unknown': sonar.projectKey

따라서 projectKey를 프로젝트 이름으로 설정해줬습니다.


sources

테스트 코드는 포함하지 않을 것이므로 분석할 코드 경로를 정하는 sourcessrc/main으로 설정하고, 추가적으로 sourceEncodingUTF-8로 적어줬습니다.


binaries

SonarQube는 자바 코드를 분석할 때 소스 코드(.java)뿐만 아니라, 컴파일된 바이너리 파일(.class)도 필요하기 때문에,

.class 파일의 경로도 설정해줘야 합니다.

이 설정을 안해주면 아래와 같은 에러가 발생합니다.

org.sonar.java.AnalysisException: Your project contains .java files, please provide compiled classes with sonar.java.binaries property, or exclude them from the analysis with sonar.exclusions property.

따라서 build/classes/java/main으로 설정했습니다.



명령어 실행

최종적으로 프로젝트 빌드 후 아래 명령어를 실행했습니다.

docker run --rm \
    -e SONAR_HOST_URL="http://host.docker.internal:9000" \
    -e SONAR_TOKEN="발급받은 토큰" \
    -v "$(pwd):/usr/src" \
    sonarsource/sonar-scanner-cli \
    -Dsonar.projectKey=프로젝트 이름 \
    -Dsonar.java.binaries=build/classes/java/main \
    -Dsonar.sonar.sourceEncoding=UTF-8 \
    -Dsonar.sources=src/main



2. 결과 분석 & 리팩토링하기

드디어 코드 분석이 끝나서 웹페이지에서 결과를 볼 수 있습니다. ♻️

위 화면은 Overviews 섹션입니다.

신뢰성, 특히 유지보수성에서 많은 이슈들이 있고 🧐 테스트 코드를 포함하지 않았더니 커버리지는 0.0%가 나왔습니다.

코드 중복도 0.3% 발견됐네요.


다음으로 Issues 섹션에서 더 자세히 살펴보면서 리팩토링을 진행해보겠습니다.

먼저 신뢰성의 3가지 이슈 모두 형변환과 관련된 내용이었습니다.

그 중 하나를 살펴보겠습니다.


(1) 연산 시 데이터 타입 보장을 위한 형변환

아래 코드에서 LocalDate 객체의 minusDays의 파라미터는 long 타입이어야 하는데, int 값이 주어지면서 결과가 예상대로 나오지 않을 위험이 있기에 신뢰성과 의도성을 해치게 되는 것입니다.

	public LocalDateTime getMondayDateTime(LocalDate pivotDate) {
		int pivotDay = pivotDate.getDayOfWeek().getValue();
		int monday = DayOfWeek.MONDAY.getValue();
		return pivotDate.minusDays(pivotDay - monday).atStartOfDay();

이를 해결하려면 두 피연산자를 최종 타입인 long으로 변환한 후 연산을 진행해야 합니다.

연산식에서 서로 다른 데이터 타입이 나타날 경우, 자바 컴파일러는 가장 큰 데이터 타입으로 통일하기 때문에 피연산자 중 하나를 long 타입으로 바꾸었습니다.

	public LocalDateTime getMondayDateTime(LocalDate pivotDate) {
		int pivotDay = pivotDate.getDayOfWeek().getValue();
		long monday = DayOfWeek.MONDAY.getValue();
		return pivotDate.minusDays(pivotDay - monday).atStartOfDay();
	}

유지보수성 관련 이슈들은 다음과 같은 리팩토링을 진행했습니다.

(2) 중복되는 값 변수로 추출하기

(3) private 생성자를 추가해 인스턴스화 방지하기

@Getter
public class APIConstants {
	private static final String VERSION = "/v1";
	public static final String API_PREFIX = "/api" + VERSION;
    
    private APIConstants() { //private 생성자
		throw new UnsupportedOperationException("Cannot be instantiated");
	}
}

사실 위 클래스는 단순히 API prefix를 적어둔 static final 필드를 모아 둔 클래스이므로 인스턴스를 생성할 이유도 실수할 가능성도 거의 없긴 하지만, 인스턴스화를 아예 막아두기 위해 private 생성자를 추가했습니다.

(4) 필요한 곳에 주석 추가하기

(5) 불필요한 변수 제거하기

(6) 컨벤션에 따라 패키지명 모두 소문자로 수정하기

roomRequestroomrequest
accessHandleraccesshandler

등의 리팩토링을 진행했습니다.




이후에는 검사 대상에 테스트 코드까지 포함시켜 JaCoCo로 커버리지를 측정하는 것과,

CI/CD 파이프라인을 구축하고 SonarQube를 연동하여 품질 검사를 자동화하는 것이 과제가 될 것 같습니다. 🙂‍↕️




참고

https://docs.sonarsource.com/sonarqube-server/latest/analyzing-source-code/scanners/sonarscanner/

profile
백엔드 개발자입니다

0개의 댓글