1. code quality improvement for C++
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을 올려놓고 (실차테스트)를 진행
- 전체 시스템의 워크플로우와 프로세스를 테스트
- 사용자가 시스템을 사용할 때 발생할 수 있는 모든 시나리오를 검증
- 비기능적 요구사항 검증
- 성능, 안정성, 보안, 사용성 등의 비기능적 요구사항에 대한 테스트를 진행
- 버그 및 결함 탐지
- 개별 모듈이나 컴포넌트에서 발견되지 않았던 시스템 전체의 결함이나 버그를 탐지하고 수정
- 배포 전 마지막 단계
- 소프트웨어 배포 전의 마지막 테스트 단계, 이 단계에서 발견된 문제는 배포 전에 수정
Coding Guideline
ISO C++ core guideline
- 장점
- C++ 표준화 위원회의 멤버들에 의해 작성
- 최신 C++ 표준과 관련된 최고의 관행을 다룬다
- 사용자 정의 타입과 모던 C++ 기능에 대한 강조
- 단점
- 초보자에게는 어려울 수 있다
- 매우 방대하고 상세하다
Google C++ Style Guide
- 보통 이걸 참조하면 좋다 (더 세세하게 하고 싶으면 ISO)
- 장점
- 실제 대규모 프로젝트에서 검증된 스타일
- 초보자에게 친숙하고 명확한 권장 사항 제공
- 단점
- google의 특정 요구 사항에 맞춰져있다
- 일부 모던 C++ 기능의 사용을 제한하거나 추천하지 않는다
LLVM Coding Standard
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를 통해 자동화하는 방법이 있다