배경
최근 몇 차례의 코드 리뷰 경험들로 공유하는 문화가 얼마나 큰 이펙트가 있는지 경험할 수 있었다.
하지만 현재 조직에서는 홀로 서버 개발을 진행하다보니 내가 작성하고 있는 코드가 과연 좋은 방향으로 나아가고 있는 것인지 혹은 구조적이나 가독성 등 좋은 코드를, 올바른 설계를 하고 있는 것일까? 라는 의구심이 생겼다.
또한, 여러 번 기술 면접을 다녀왔는데 많은 조직에서 내부적으로 소나 큐브를 정적 코드 분석 도구로 활용하고 있었다.
소나큐브를 통해 받을 수 있는 코드 리뷰를 통해 코드 품질 향상과 더불어, 코드 일관성 등의 컨벤션도 정립하고자 도입하게 되었다.
설치
(사용중인 호스트 서버는 ubuntu 20.04.1 이며, 도커를 이용하여 세팅했다.)
docker run -d --name sonarqube -p 9000:9000 sonarqube
위 명령어를 통해 바로 설치와 실행을 해준다. docker run 명령을 실행할 때 로컬에 이미지가 없으면 도커 허브에서 자동으로 이미지를 다운로드하고 실행시킨다. (특정 버전을 사용해야한다면 이미지를 특정 버전으로 설치한 후 실행한다.)
소나 큐브의 웹 콘솔은 기본적으로 9000 포트를 사용하는 것 같다. 현재 해당 포트를 사용하지 않기 때문에, 포트포워딩을 통해 9000번 포트로 접근할 수 있도록 설정하였다.
세팅
admin/admin으로 접속할 수 있었고, 로컬 프로젝트를 바로 생성해주었다.
간단하게 과정들을 캡처했는데, 간단하게 세팅할 수 있었고 안내를 너무 잘해줘서 쉽게 세팅할 수 있었다.
설정을 마치고나면, 분석 방법에 대한 설정을 하게 된다.
현재 배포 파이프라인이 Actions을 통해 구성되어있으므로 Actions를 선택했다.
기존 배포 프로세스와 겹치지 않게, 별도의 Actions 스크립트로 구성해서 셋팅을 완료했다.
분석받기
아무 설정도 하지 않았을 때, 현재 코드가 Passed된 모습이고
보안, 신뢰성, 유지보수성, 코드 중복, 커버리지 등 상세하게 문제지점을 볼 수 있다.
Measures 탭이 있는 걸 보니, 뭔가 새로운 코드가 반영됐을 때 이전 상태와 비교해서 개선이 되었는지도 측정해주는 것 같다.
누르고 싶게 생긴 빨간 Security Hotspots를 살펴봤다.
위 코드는 테스트나 로컬 환경에서의 여러 스키마를 synchronized하는 설정 코드이다. 로컬 / 테스트 환경에서만 동작하는 코드이기 때문에 딱히 수정할 필요가 없을 수 있다.
아래 코드는 이미지를 랜덤으로 가져오는 코드이며, 단순 10장 중 랜덤 한장을 보여주기만 하기 때문에 Math.random을 사용해도 PRNG 사용 등의 가능성을 고려하지 않아도 된다.
// sonar-ignore-start
connection.query(`CREATE DATABASE IF NOT EXISTS \`${databaseName}\``);
// sonar-ignore-end
(분석기가 경고하지 않게 만들 수도 있다고....)
간단하게 도커 컨테이너로 소나큐브를 구성하고, 현재 서비스의 메인 브랜치 코드를 관리할 수 있게 되었다.
과하게 의존하진 않더라도, 소나큐브가 제공하는 코드 분석의 결과가 긍정적이라면, 적극적으로 수용하여 계속해서 나은 코드, 설계에 대한 방향성을 고민하고 적용해나갈 수 있게 되었다. 소나큐브의 분석 스타일을 커스터마이징하여 프로젝트 내의 일관적인 컨벤션을 유지할 수 있게 구성해서 사용해보아야겠다.
커버리지 세팅
11월 14일 현재, 어느정도 커버리지에 대한 세팅을 하여 사용중이다.
테스트 커버리지와 동일한 커버리지를 받아볼 수 있으면서, 테스트 코드 자체는 분석이 되게 구성하였다.
# 프로젝트 기본 정보
sonar.projectKey=iwedding-api-v2
sonar.projectName=IWedding API v2
sonar.projectVersion=1.0
# 분석 경로 설정
sonar.sources=src
sonar.tests=test
# 커버리지 경로 설정
sonar.javascript.lcov.reportPaths=coverage/lcov.info
# 커버리지에서 제외할 파일
sonar.coverage.exclusions=**/*.config.ts, **/*.module.ts, \
**/*.interface.ts, **/*.dto.ts, **/*.constant.ts, **/*.enum.ts \
**/*.error.ts, **/*.exception.ts \
src/**/*.error.ts, src/**/*.exception.ts, \
src/infra/database/**, \
src/main.ts, \
src/**/entity/**/*.ts, \
src/**/enum/**/*.ts, \
src/**/interface/**/*.ts, \
src/**/type/**/*.ts, \
src/**/*.config.ts, \
src/**/*.const.ts, \
src/common/error/**/*.ts, \
test/**/*.ts # 테스트 파일 커버리지 제외
# 소스 인코딩
sonar.sourceEncoding=UTF-8
# TypeScript 설정
sonar.typescript.tsconfigPath=tsconfig.json
실제 서비스의 백엔드 프로젝트의 루트 경로에 위와 같은 프로퍼티 파일을 생성해서 소나큐브가 읽을 수 있게 구성하여 사용중이다. 소나큐브의 커버리지는 jacoco와 연동해서 많이들 사용하던데, node이기 때문에 Jest를 사용하였다.
소나큐브 Actions 스크립트에서 test를 돌리기 위해서는 DB와 기타 서드파티를 도커로 구성하여 띄워야 소나큐브에서도 테스트를 돌려 커버리지 파일을 동적으로 활용할 수 있을텐데, 그 작업은 뒤로 미루고 메인 브렌치에서 pre-commit 단계에서 실행되는 테스트에 커버리지 파일을 생성하여 coverage/lcov.info는 ignore하지 않고 레포에 같이 올려서 사용중이다.
(더 추가적인 세팅이 완료되면, 1차적으로 해당 포스팅에 이어 작성하고, 분량이 많아지면 정리하여 새로운 포스팅으로 정리하자.)
2023.04 ~ 백엔드 개발자의 기록
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!