GitHub News

GitHub 코드 스캔으로 개발자 만족도 높이기

GitHubKorea 2022. 10. 17. 10:26

안녕하세요, GitHub 한국 총판 단군소프트입니다.
오늘의 GitHub 소식, 'GitHub 코드 스캔으로 개발자 만족도 높이기'에 대한 주제로 찾아뵙게 되었습니다 :)

그럼 시작해 볼까요?

GitHub 코드 스캔 기능을 사용하여 코드를 보호하는 방법은 이미 알고 계실 수 있습니다. 하지만 일상적인 코딩 작업을 쉽게 하기 위해 사용하는 것은 어떨까요? GitHub는 코드 스캔을 위한 코드 분석 엔진인 CodeQL을 내부적으로 사용하고 있으며, 코딩 실수를 방지하여 코드 품질을 높게 유지하고 있습니다. 이와 관련하여 아래에서 CodeQL을 최대한 활용할 수 있는 방법에 대한 몇 가지 예시를 확인해 보시기 바랍니다.


메모리 누수 방지

Go언어의 defer문은 주변 함수가 반환될 때까지 해당 함수의 실행을 지연시킵니다. 해당 구문은 예를 들어, 파일 핸들 등의 리소스를 종료하거나 데이터베이스 트랜잭션을 완료하는 등 정리하는 데 유용합니다.

기존 코드를 변경할 때 실수로 루프 내에서 defer 문을 같이 이동할 수 있습니다. 하지만 이 경우에도 함수가 종료될 때까지 대기해야 하기 때문에 루프문이 종료될 때까지 작업이 수행되지 않습니다. 이런 실수가 운영환경에서 메모리 누수로 이어지는 경우가 종종 발생합니다.

만약 이러한 실수를 미리 지적할 수 있다면 어떨까요? 코드 스캔 기능은 CodeQL 4줄로 이러한 실수를 검출할 수 있습니다.

위의 예시의 후기로는 같은 실수를 겪던 다른 GitHub 개발팀에서 팀 내의 저장소에 코드스캔 기능을 활성화하고 위 CodeQL 쿼리문을 추가하였습니다. 추가로, 코드스캔을 활성화하고 팀은 CodeQL 쿼리문이 검출한 다른 문제가 있었는데요, 다음 문단에서 이야기해보도록 하겠습니다.

 

무시할 수 없는 오류

일부 코드베이스에서는 Go Object Relational Mapper인 GORM을 사용합니다. GORM에서의 에러 처리는, 체인이 가능한 API를 가지고 있기 때문에, 일반적인 Go 코드와는 다릅니다.

다음은 예시 문입니다.
if err := db.Where("name = ?", "jinzhu").First(&user).Error; err != nil { // error handling... }

db.Where("name = ?", "jinzhu").First(&user)와 같은 코드는 Error 필드를 생각하지 않고 작성하는 실수가 많은데요, 이러한 실수를 검출하는 CodeQL 쿼리문은 Pull Request 중 실수를 검출할 수 있습니다. 포인터를 반환하는 비슷한 쿼리문들은 다음 링크를 확인해보세요.



루프 구문 퍼포먼스 문제

위와 같은 누락된 오류 검사로부터의 보호 뿐만 아니라 데이터베이스 쿼리 코드 성능도 유지해야 하는데요, 일반적으로 "N+1 쿼리"는 성능 문제를 일으킬 수 있습니다. 집합의 모든 멤버에 대해 한 번씩 비용이 많이 드는 작업이 수행되기 때문에 항목 수가 증가할수록 코드가 느려집니다. 여기서는 대부분의 경우 루프 내의 데이터베이스 쿼리문이 원인입니다. 일반적으로 루프 외부의 배치 쿼리를 사용하면 퍼포먼스가 향상됩니다.

다음 링크는 저희가 작성한 CodeQL 쿼리입니다. 이 쿼리는 실제로 실행되는 GORM 메서드에 대한 콜을 검색합니다. 이 콜 리스트를, 루프내에서 발생하는 콜 리스트로 필터링 후, 필터에 포착된다면 CI를 실패합니다. CodeQL의 장점은 루프 본체 내에서 데이터베이스 콜에 한정되지 않고 루프에서 직접 또는 간접적으로 호출된 함수 내의 콜도 포착된다는 것입니다.
 

 

루프 구문 퍼포먼스 문제

아래 쿼리문들은 실험적인 것으로 CodeQL 데이터베이스에는 포함되어 있지 않습니다만, 저희가 생성한 특수 쿼리 데이터베이스를 참조하여 사용할 수 있습니다.

먼저 분석하려는 저장소에 .github/codeql/go-developer-happiness.qls 파일을 아래 내용으로 생성합니다.
- import: codeql-suites/go-developer-happiness.qls from: codeql-go

다음으로 CodeQL 워크플로를 작성(또는 기존 워크플로를 수정합니다)하고 아래와 같이 Initialize CodeQL 단계를 추가합니다.
- name: Initialize CodeQL uses: github/codeql-action/init@v1 with: languages: go queries: ./.github/codeql/go-developer-happiness.qls

자세한 내용과 예시는 다음 링크 참조 부탁드립니다.


나만의 쿼리문 작성

코드베이스에 추가할 커스텀 CodeQL 쿼리문이 있다면 다음 문서와 커뮤니티에서 자세히 다루고 있습니다.
여러분의 의견을 기다리고 있습니다!



출처 : https://github.blog/2021-09-07-increasing-developer-happiness-github-code-scanning/