프로그래밍 언어/C++

c++로 쓰여진 코드를 리팩토링 하는 방법

해달이랑 2024. 9. 26. 00:05

코드 리팩토링을 하는 방법

1. 주석과 문서화 개선

  • 코드 내에 중요한 부분이나 복잡한 로직에 대해 주석을 추가합니다.
  • 함수, 클래스, 변수의 역할을 명확히 설명하는 문서화를 추가합니다.

2. 함수 분리와 재사용성 향상

  • 긴 함수는 작은 함수로 분리합니다. 각 함수는 하나의 작업만 수행하도록 합니다.
  • 중복 코드를 제거하고 공통된 로직을 함수로 분리해 재사용성을 높입니다.

3. 의미 있는 변수와 함수 이름 사용

  • 변수와 함수 이름은 그 역할을 명확히 나타내도록 의미 있는 이름을 사용합니다.
  • int a 보다는 int userAge 같은 이름이 더 좋습니다.

4. Magic Number 제거

  • 코드에 하드코딩된 숫자 값들을 상수로 치환합니다.
  • 예를 들어 #define PI 3.14159 또는 const double PI = 3.14159;로 정의하여 사용합니다.

5. 적절한 데이터 구조 사용

  • 더 나은 성능과 가독성을 위해 적절한 데이터 구조(예: std::vector, std::map, std::set 등)를 사용합니다.
  • 불필요한 배열 대신 STL 컨테이너를 사용하여 코드의 유연성을 높입니다.

6. 반복 패턴과 조건문 최적화

  • 반복되는 조건문과 반복문을 최적화합니다.
  • 예를 들어, 여러 if-else문을 사용할 때는 switch문이나 함수 포인터를 활용할 수 있습니다.

7. 메모리 관리 개선

  • 동적 메모리 할당을 사용할 때는 new와 delete를 적절히 사용하여 메모리 누수를 방지합니다.
  • 가능하면 std::unique_ptr, std::shared_ptr 같은 스마트 포인터를 사용해 메모리 관리를 자동화합니다.

8. 클래스 구조 개선

  • 큰 클래스는 기능별로 분리하여 관리하기 쉽게 합니다.
  • 객체 지향 원칙(SOLID 원칙 등)을 따르는 클래스를 설계합니다.
  • 필요 없는 public 메서드를 private으로 전환하거나 제거합니다.

9. 코드 스타일 일관성 유지

  • 일관된 코드 스타일을 유지합니다(예: 공백, 중괄호 위치, 인덴트 등).
  • 팀 내에서 정해진 코딩 컨벤션을 따릅니다.

10. 컴파일러 경고 제거

  • 모든 컴파일러 경고를 해결합니다.
  • 이는 버그의 잠재적인 원인을 제거하는 데 도움이 됩니다.

11. 테스트 코드 추가

  • 리팩토링 후에도 코드가 올바르게 작동하는지 확인하기 위해 유닛 테스트를 작성합니다.
  • 지속적인 리팩토링과 테스트를 통해 코드의 신뢰성을 높입니다.

12. 설계 패턴 적용

  • 프로젝트에 적합한 설계 패턴(예: Singleton, Observer, Factory)을 적용하여 코드 구조를 개선합니다.

헤더 파일 분리

1. 헤더 파일 분리

  • 역할에 따라 분리: 헤더 파일을 기능별로 분리합니다. 예를 들어, 데이터 구조체와 관련된 것들은 data_structures.hpp에, 함수 선언들은 functions.hpp에, 상수나 전역 변수들은 constants.hpp에 따로 정의할 수 있습니다.
  • 의존성 최소화: 헤더 파일 간의 의존성을 줄이기 위해, 각 헤더 파일이 독립적으로 동작하도록 만듭니다. 필요하다면, 전방 선언(forward declaration)을 사용해 의존성을 줄입니다.

2. 네임스페이스 사용

  • 네임스페이스를 사용하여 코드를 논리적으로 그룹화할 수 있습니다. 예를 들어, 데이터 처리와 관련된 구조체와 함수를 DataProcessing 네임스페이스 안에 두고, 유틸리티 함수는 Utilities 네임스페이스에 두는 방식으로 코드를 정리합니다.
  • 이를 통해 코드를 더 명확하게 하고, 다른 모듈에서의 충돌을 방지할 수 있습니다.

3. 클래스로 그룹화

  • 관련된 구조체와 함수를 하나의 클래스 안으로 통합할 수 있습니다. 클래스는 데이터를 캡슐화하고 메서드를 제공하므로, 코드를 보다 구조화되고 유지보수하기 쉽게 만듭니다.
  • 예를 들어, 특정 데이터 타입과 그에 관련된 함수들을 하나의 클래스로 묶어 두면, 그 클래스 외부에서는 데이터에 직접 접근하지 않고 메서드를 통해서만 접근하게 할 수 있습니다.

4. PIMPL(Idiom) 패턴 적용

  • 헤더 파일에 많은 구현 세부사항이 있을 경우, PIMPL(Private Implementation) 패턴을 적용하여 구현 세부사항을 소스 파일로 옮길 수 있습니다. 이 방식은 헤더 파일의 크기를 줄이고, 컴파일 시간을 단축시키는 장점이 있습니다.
  • 예를 들어, 클래스의 멤버 변수를 헤더 파일에 공개하지 않고, 구현 파일에서 std::unique_ptr 등을 사용하여 관리할 수 있습니다.

5. 모듈화

  • 큰 프로젝트의 경우 모듈화가 필요할 수 있습니다. 특정 기능들을 독립된 모듈로 분리하고, 각 모듈에 대해 별도의 헤더 파일과 소스 파일을 제공하는 방식입니다.
  • 모듈화된 코드는 독립적으로 개발, 테스트, 유지보수할 수 있어 전체 프로젝트의 복잡도를 줄일 수 있습니다.

6. 전역 변수 최소화

  • 전역 변수를 남용하는 것은 유지보수와 디버깅을 어렵게 만들 수 있습니다. 전역 변수는 가능한 한 사용을 자제하고, 필요할 경우 클래스의 멤버 변수나 함수의 인자로 전달하여 사용합니다.
  • 불가피하게 전역 변수를 사용해야 한다면, 이를 별도의 헤더 파일로 분리하여 다른 코드와의 의존성을 명확히 합니다.

7. 인클루드 가드 추가

  • 헤더 파일에는 인클루드 가드를 추가하여 동일한 헤더 파일이 여러 번 포함되는 것을 방지합니다. 인클루드 가드는 일반적으로 다음과 같이 사용됩니다:
#ifndef MY_HEADER_FILE_HPP
#define MY_HEADER_FILE_HPP

// 헤더 파일 내용

#endif // MY_HEADER_FILE_HPP

 

8. 파일 크기 제한

  • 헤더 파일의 크기를 제한하는 것도 좋습니다. 일반적으로, 하나의 헤더 파일이 너무 커지지 않도록 하고, 이를 적절히 분할하여 관리하는 것이 좋습니다.
  • 파일당 약 300~500 라인 이하로 유지하려고 노력합니다.