1. code quality improvement for C++

happy_quokka·2023년 11월 27일

C++

목록 보기
1/3

1. background

The importance of code quality

  • 품질 높은 코드는
    • 더 안정적
    • 유지 보수가 쉬움
    • 오류 발생 확률이 적음
  • 이점
    • 유지보수성
      • 품질이 높은 코드는 이해하기 쉽고 수정하기 편리
      • 변경 사항을 더 쉽게 적용 가능하게 한다
    • 안정성
      • 버그 발생 확률이 감소
      • 사용자 경험을 향상시키고 다양한 환경에서의 안정적인 작동 보장
    • 효율성
      • 자원을 효율적으로 활용
      • 성능 문제 최소화
    • 재사용성
      • 잘 구조화되고 모듈화된 코드는 다른 프로젝트나 컨텍스트에서 재사용하기 쉽다
      • 개발시간, 비용 절약 가능
    • 확장성
      • 새로운 기능, 요구 사항을 추가하기 쉽다
      • 확장성있는 설계는 시스템이 성장하거나 변화할때 유연하게 대응할 수 있게 한다
    • 협업
      • 깔끔하고 일관된 코드
      • 다른 개발자가 코드를 쉽게 이해하고 수정 가능
    • 긴밀한 통합
      • 다른 시스템과의 통합도 더 간결
    • 고객 만족
      • 버그가 적고, 성능이 좋은 제품 -> 사용자의 만족도 높인다
    • 비용 절감
      • 프로젝트 전체 수명 주기에 걸친 비용을 절약 가능
      • 버그 수정, 재작업, 운영 중인 시스템의 문제 해결 등의 비용 감소
    • 프로젝트의 성공
      • 시간 내에 예산을 준수하며 프로젝트 목표를 달성하는데 도움이 된다

어떻게 향상?

  • coding guideline
    • c++ 프로그래밍에서 일관성을 유지하고 오류를 줄이기 위한 규칙 및 모범 사례의 모음
    • 가이드라인은 가독성, 유지 보수성, 코드의 안정성을 향상시키는데 도움이 된다

일반적인 경우

  • 명명 규칙 naming convention
    • 변수, 함수, 클래스, 열거형 등에 대한 명명 규칙을 설정
    • camelCase, snake_case 등의 표준을 선택하고 일관성 있게 사용
  • 타입 안정성
    • 강력한 타입을 사용하여 오류를 줄인다
    • typedef나 using보다 새로운 타입을 정의하는 것을 선호
  • 리소스 관리
    • 자율주행의 경우 동적할당을 아에 안쓰는 경우가 많다
    • RAII 패턴을 사용하여 자월 누수를 방지
    • 스마트 포인터, std::unique_ptr, shared_ptr을 사용하여 메모리 관리를 자동화
  • 템플릿 및 제너릭 프로그래밍
    • 타입 요구사항을 명확히 기술
  • 예외처리
    • 현업에서 중요
    • 예외를 사용하여 오류를 처리하고 예외를 무시하거나 숨기지 않는다
    • 예외 안정성을 고려한 코드 작성
  • 성능
    • 불필요한 복사를 피하기 위해 이동 시멘틱을 활용
    • 성능이 중요한 부분을 profiling 후 최적화
  • 코드 구조 및 설계
    • 코드를 모듈화하고 재사용 가능하도록 설계
    • 객체 지향 설계 원칙을 따른다
  • 문서화
    • 함수, 클래스, 모듈에 대한 주석을 통해 문서화
    • 문서화 도구를 사용하여 API 문서를 자동화
  • Test
    • 유닛 테스트를 작성하여 코드의 정확성을 검증
    • TDD 같은 접근 방식을 고려 가능
  • 버전 관리
    • 코드 변경 사항을 추적하고 관리하기 위해 버전 관리 시스템 사용

Static Analysis (정적 검증)

  • 사전에 문제를 알려주는것 , coding convention 또는 format과 다를 때 사전에 알려준다 (정적검증에 이것을 등록시켜 놓은 경우)
  • 실행시키지 않고 코드를 구조, 문법, 코드 표준 준수, 잠재적 오류 및 다른 품질 관련 문제를 검사하는 과정
  • 정적 검증은 주로 컴파일 타임에 발생하며, 다양한 도구와 방법론을 사용하여 수행
  • local : 보통 빌드, 컴파일에 엮어놓고 검증한다
  • 회사 : 깃헙상에 pr 올라갈 때 검증하고 pr을 올릴 수 있게 한다

특징

  • 코드 품질 향상
    • 코드 일관성, 가독성, 유지보수성을 향상 가능
  • 조기 오류 탐지
    • 코드 실행 전에 문제점을 발견하여 런타임 오류의 가능성을 줄여준다
  • 코드 표준 준수
    • 회사, 프로젝트의 코딩 가이드라인 및 표준을 준수하는지 확인
  • 보안 문제 탐지
    • 특정 패턴의 보안 취약점을 감지하고 개발자에게 해당 문제점을 지적
  • 복잡도 측정
    • 코드의 복잡도나 다른 매트릭을 분석하여 코드의 품질을 평가
    • 불필요한 함수 호출, 메모리 사용을 방지
    • 커버리지(함수 하나를 작성했을 때 하나의 if문에만 계속 true가 되는경우) 확인
  • 코드 리뷰 지원
    • 리뷰의 효율성을 높일 수 있다 (정적 검증이 미리 체크해주기 때문)

방법

  • linters
    • 코드의 문법, 스타일 및 일부 로직 오류를 검사하는 도구
    • 잘 구현된 linter는 auto-formating을 지원한다
  • 정적 분석 도구
    • 코드의 품질, 복장성, 잠재적 오류, 보안 취약점 등을 분석하는 도구
  • 코드 리뷰
    • 개발자들이 수동으로 코드를 검사하고 평가하는 과정
    • 컴퓨터가 로직을 확인해주지 못하기 때문에 사람 확인해야한다
  • 코드 표준 및 가이드라인 검사
    • 회사, 프로젝트에서 정한 코딩 표준 및 가이드라인을 준수하는지 검사

Dynamic Analysis (동적 검사)

  • 만들어진 프로그램이 제대로 동작하는지 전체적인 프로그램의 퍼포먼스를 분석
  • 소프트웨어의 실행 중인 동작을 실시간으로 모니터링하고 분석하는 방법
  • 실행 중인 프로그램의 동작을 정확하게 이해할 수 있고, 잠재적인 문제점이나 위험성을 파악 가능

특징

  • 실시간 분석
    • 코드의 실제 동작이 어떻게 이루어 지는지
    • 프로그램이 실제로 실행되는 동안의 동작을 분석하기 때문에 코드의 실제 동작 방식와 관련된 문제점을 파악하는데 유용
  • 메모리 관리 문제 탐지
    • 동적 검증은 메모리 누수, 이중 해제, 배열의 경계를 넘어거는 접근 등의 메모리 관련 문제를 탐지 가능
  • 동시성 문제 탐지
    • 다중 스레드 환경에서 발생할 수 있는 경쟁 조건, 데드락, 스레드 안정성 문제 등을 분석하고 탐지
    • 데이터 레이싱 문제 탐지
  • 리소스 사용 분석
    • 파일 핸들, 네트워크 연결, 데이터베이스 연결 등의 리소스를 사용과 관련된 문제를 모니터링하고 분석
    • seg fault의 위험을 가지고 있을 때 검증할 수 있다
  • 안전하지 않은 동작 탐지
    • 프로그램에서 잠재적으로 위험한 동작이나 취약점을 감지 가능
  • 퍼포먼스 모니터링
    • 프로그램의 성능 병목이나 비효율적인 동작을 식별하는데 도움을 준다
    • profiler라는 툴로 모니터링
  • 정적 검증은 pr 올라가기전에 확인
  • 동적 검증도 pr -> review -> CI -> merge
  • CI : 특정 타겟에 대한 데이터세트 동작속도, 정확도, 메모리 이슈 졸았다....
  • CI가 중요하다. 퍼포먼스 차이가 엄청 난다
  • 개발 프로세스에 통합하는 작업을 알면 좋다

Test

  • 코드의 정확성, 효율성, 안정성을 검증하기 위한 과정을 나타낸다
  • 자동화된 테스트 도구와 라이브러리를 사용하여 코드의 다양한 부분을 테스트 진행

Test 종류

  • 유닛 테스트 (unit test)
    • 특정 모듈, 함수, 클래스 또는 메서드의 개별 기능을 검증하는 것을 목적으로 한다
    • 주어진 입력에 대해 예상되는 출력이나 동작을 반환하는지 확인하는 것
    • 특징
      • 독립성
        • 각 테스트 케이스는 다른 테스트 케이스와 독립적으로 실행되어야 한다
        • 하나의 테스트 실패는 다른 테스트에 영향을 주어서는 안된다
      • 자동화
        • 유닛 테스트는 자동으로 실행될 수 있어야한다
      • 빠른 실행
        • 소요시간이 적어야한다
        • 이를 통해 개발자는 코드 변경 후에 빠르게 피드백을 받을 수 있다
  • 통합 테스트 (Integration Test)
    • 개별 컴포넌트, 모듈 또는 시스템의 독립된 용분들이 서로 올바르게 통합되어 작동하는지 확인
    • 서로 다른 컴포넌트들이 함께 작동할 때 발생할 수 있는 문제점을 발견하기 위해 수행
    • 모듈 간의 계층구조를 잘 나누어 놓는 것이 중요
    • 특징
      • 모듈 간 상호작용
        • 유닛 테스트는 개별 모듈이나 함수에 초점을 맞추지만
        • 통합 테스트는 여러 모듈이나 시스템 간의 상호 작용을 테스트
      • 의존성 확인
        • 서로 다른 시스템 또는 서비스 간의 통신, 데이터 베이스 연결, 파일 시스템 접근 등의 의존성을 검증
        • 여러 함수에서 데이터가 꼬이지 않는지
      • 자동화와 수동 테스트
        • 통합 테스트는 자동화할 수 있지만 일부 복잡한 상호작용은 수동으로 테스트하는 것이 적절할 수 있다
        • 유닛은 모두 진행되어야하지만 통합 테스트는 실제 필요한 경우에만 진행하면 된다
  • 퍼포먼스 테스트
    • 우리는 작성할 일이 별로 없다. 보통 검증해주는 팀이 해준다
    • 소프트웨어의 성능 측정을 측정하고 평가하기 위한 테스트
      • 사용자의 요구 사항을 충족시키기 위해 시스템이 얼마나 빠르게 반응하는지
      • 얼마나 많은 작업량을 처리할 수 있는지
    • 실제 동작 시간을 만족하는지, 멀티 스레드로 성능이 저하되지 않는지, 메모리 사용량에 문제가 없는지 확인
    • 특징
      • 반응 시간 측정
        • 특정 요청에 대한 시스템의 반응 시간을 측정
      • 시스템의 한계 확인
        • 시스템이 처리할 수 있는 최대 작업량을 의미
        • 반복해서 실행했을 때 계속 잘 작동하는지
        • 하드웨어랑 연관
      • 성능 병목 찾기
        • 동적 검증에서도 확인 가능
        • 시스템의 성능을 저하시키는 요소를 찾아내고 이를 최적화
    • 유형
      • 부하 테스트
        • 정의된 기대 작업량 내에서 시스템의 성능을 평가
      • 스트레스 테스트
        • 시스템의 한계를 넘어서는 작업량을 부여하여 시스템이 어떻게 반응하는지 확인
      • 내구성 테스트
        • 시스템에 지속적으로 부하를 주어 시간이 지난 후의 성능을 확인
        • 스트레스 테스트의 일종
  • 시스템 테스트
    • 프로그램 자체에 대한 테스트
    • 유닛, 통합이 합쳐져서 전체 시스템에 대한 시나리오는 만들고 이것이 문제없이 잘 돌아가는지 테스트
    • 개별 모듈이나 컴포넌트의 통합 후 전체 시스템의 완전성, 기능, 및 성능을 검증
    • 개별 모듈 또는 컴포넌트의 독립적인 테스트를 넘어서 전체 소프트웨어 또는 시스템의 동작을 평가하는 것을 목표
    • CI 에서 마지막에 test도 진행하는데 여기에 유닛테스트, 시스템 테스트가 꼭 들어간다
    • 특징
      • 전체 시스템 검증
        • 시스템 테스트는 모든 컴포넌트와 모듈이 함께 동작할 때 전체 시스템이 제대로 동작하는지 확인
      • 사용자 요구사항 검증
        • 시스템 테스트는 주로 사용자, 클라이언트의 요구사항과 명세에 따라 진행
        • 이를 통해 개발된 소프트웨어가 실제 사용자의 기대와 요구를 만족시키는지 평가
      • end to end 테스트
        • 실제 자동차에 SLAM을 올려놓고 (실차테스트)를 진행
        • 전체 시스템의 워크플로우와 프로세스를 테스트
        • 사용자가 시스템을 사용할 때 발생할 수 있는 모든 시나리오를 검증
      • 비기능적 요구사항 검증
        • 성능, 안정성, 보안, 사용성 등의 비기능적 요구사항에 대한 테스트를 진행
      • 버그 및 결함 탐지
        • 개별 모듈이나 컴포넌트에서 발견되지 않았던 시스템 전체의 결함이나 버그를 탐지하고 수정
      • 배포 전 마지막 단계
        • 소프트웨어 배포 전의 마지막 테스트 단계, 이 단계에서 발견된 문제는 배포 전에 수정

2. tools for Code Quality Improvement

Coding Guideline

ISO C++ core guideline

  • 장점
    • C++ 표준화 위원회의 멤버들에 의해 작성
    • 최신 C++ 표준과 관련된 최고의 관행을 다룬다
    • 사용자 정의 타입과 모던 C++ 기능에 대한 강조
  • 단점
    • 초보자에게는 어려울 수 있다
    • 매우 방대하고 상세하다

Google C++ Style Guide

  • 보통 이걸 참조하면 좋다 (더 세세하게 하고 싶으면 ISO)
  • 장점
    • 실제 대규모 프로젝트에서 검증된 스타일
    • 초보자에게 친숙하고 명확한 권장 사항 제공
  • 단점
    • google의 특정 요구 사항에 맞춰져있다
    • 일부 모던 C++ 기능의 사용을 제한하거나 추천하지 않는다

LLVM Coding Standard

  • 장점
    • LLVM 프로젝트와 관련된 가이드라인

Mozilla C++ coding style

  • Mozilla : firefox를 만든 회사
  • 장점
    • 웹 브라우저와 관련된 대규모 프로젝트에서 검증된 스타일
    • 코드 가독성과 안정성에 중점
  • 단점
    • Mozilla 프로젝트의 특정 요구 사항에 초점

Static Analysis

clang static analyzer

  • 장점
    • LLVM / Clang 기반임으로 최신 C++ 표준에 대한 훌륭한 지원
    • 무료 및 오픈소스
    • 컴파일러를 깔면 자동으로 설치된다
    • 깔끔한 출력과 명확한 버그 리포트
  • 단점
    • 일분 오래된 코드베이스나 플랫폼에서는 적합하지 않을 수 있다

Cppcheck

  • 장점
    • 간단한 설치 및 사용
    • 무료 및 오픈소스
  • 별도로 설치해야한다
  • 여기서부터는 유료

Coverity

  • 장점
    • 광범위한 분석 및 상세한 리포트
    • 큰 프로젝트와 복잡한 코드 베이스에 적합
  • 단점
    • 무료 버전이 제한적이다
    • 비용이 발생할 수 있다

PVS-Studio

  • 장점
    • 상세하고 광범위한 분석
    • 지속적인 업데이트 및 최선 C++ 표준 지원
  • 단점
    • 비용
    • 처음 사용하는데 학습 곡선이 있을 수 있다

SonarQube

  • 유료 중에 추천한다
  • 장점
    • 다양한 언어 지원
    • thirdparty에 대한 지원을 많이 해준다
    • 웹 기반 인터페이스로 코드 품질 대시보드 제공
  • 단점
    • 완전한 C++ 지원을 위해서는 상용 플러그인 필요
    • 설정과 통합이 복잡할 수 있다

Dynamic analysis

Valgrind

  • 추천
  • 장점
    • 메모리 누수, 사용 전 초기화되지 않는 메모리 사용, 메모리 오버런 등의 문제 탐지
    • 무료 및 오픈소스
    • 상세한 리포트 제공
  • 단점
    • linux와 macOS에 주로 사용됨 (window 지원은 제한적)
    • 프로그램 실행 속도가 상당히 느려짐 (사실 모든 동적검증 툴의 문제)

그외

  • addressSanitizer
  • Dr.Memory
  • Intel Inspector

Test

Google Test (GTest)

  • google에서 개발된 C++을 위한 단위 테스트 프레임워크
  • 장점
    • 쉬운 설치와 사용
    • 매크로 기반의 테스트 케이스 정의
    • 다양한 assert 메서드 제공
    • mocking 지원을 위한 google mock과 통합이 용이하다
  • 단점
    • 일부 사용자는 매크로 기반의 접근 방식을 선호하지 않음

Boost.Test

  • 권장하지 않는다
  • 라이브러리 용량이 엄청 크다

Catch2

  • 장점
    • 설치 간단, 사용이 쉽다
    • 매크로 없이 자연스러운 테스트 케이스 작성이 가능
    • BDD(Behavior-Driven Development) 스타일의 테스트도 지원
  • 단점
    • 호환성에 문제가 있을 수 있다(아마 옛날 버전과)

CppUnit

  • C++의 전통적인 단위 테스트 프레임워크
  • 장점
    • 많은 시스템과 IDE에서 지원
    • 테스트의 구조화와 재사용성에 중점
  • 단점
    • 다른 현대적인 프레임워크에 비해 기능, 유용성에서 뒤떨어질 수 있다

3. Documentation

doxygen

  • 이거 사용!
  • 여러 언어의 소스 코드 문서화를 위한 표준 도구
  • 주석 안에 특별한 태그를 사용하여 코드에 직접 문서화 정보를 추가 가능
  • HTML, LaTex, RTF, XML, man 페이지 등 다양한 포맷으로 문서를 출력 가능
  • 그래프와 함께 클래스 관계도를 생성 가능(Grapphviz와 통합됨)
  • 주석만 만들면 문서를 만들어준다
  • cmake를 통해 자동화하는 방법이 있다

0개의 댓글