Post

리팩토링을 어떤 식으로 하나?

리팩토링을 어떤 식으로 하나?

리팩토링(Refactoring)은 코드의 기능을 변경하지 않으면서 내부 구조를 개선하여 가독성, 유지보수성, 확장성을 향상시키는 작업입니다. 잘된 리팩토링은 코드의 품질을 높이고, 개발자가 더 효율적으로 작업할 수 있게 합니다. 아래는 리팩토링을 진행하는 방법과 주요 기법에 대한 자세한 설명입니다.

1. 리팩토링의 필요성

  • 가독성 향상: 복잡하고 이해하기 어려운 코드를 쉽게 읽을 수 있도록 개선합니다.
  • 유지보수성 증가: 코드를 쉽게 수정하고 확장할 수 있도록 합니다.
  • 버그 감소: 코드 구조를 명확히 하여 버그를 줄입니다.
  • 재사용성 향상: 중복 코드를 제거하고, 모듈화하여 재사용성을 높입니다.

2. 리팩토링의 원칙

  • 작은 단계로 진행: 리팩토링은 작은 단계로 진행하여, 각 단계에서 기능이 유지되도록 합니다.
  • 테스트 주도 개발(TDD): 리팩토링 전후에 테스트를 수행하여 코드가 올바르게 동작하는지 확인합니다.
  • 단계적 개선: 전체 코드를 한 번에 리팩토링하지 말고, 부분적으로 개선해 나갑니다.

3. 리팩토링의 단계

3.1. 코드 분석

  • 코드 이해: 리팩토링할 코드를 이해하고, 주요 기능과 흐름을 파악합니다.
  • 코드 스멜(Code Smells): 코드 스멜을 식별하여 개선이 필요한 부분을 찾습니다.

3.2. 테스트 작성

  • 단위 테스트: 리팩토링 전후의 코드가 동일하게 동작하는지 확인하기 위해 단위 테스트를 작성합니다.
  • 테스트 커버리지: 코드의 주요 부분이 테스트로 커버되는지 확인합니다.

3.3. 리팩토링 수행

  • 코드 스멜 제거: 식별된 코드 스멜을 제거하는 리팩토링 기법을 적용합니다.
  • 단계적 리팩토링: 작은 단위로 리팩토링을 진행하고, 각 단계마다 테스트를 수행합니다.

3.4. 테스트 및 검증

  • 테스트 실행: 모든 테스트를 실행하여 리팩토링 후 코드가 올바르게 동작하는지 확인합니다.
  • 코드 리뷰: 다른 개발자와 코드 리뷰를 통해 리팩토링이 제대로 이루어졌는지 검토합니다.

4. 주요 리팩토링 기법

4.1. 코드 스멜 제거 기법

  • 중복 코드 제거: 동일하거나 유사한 코드를 함수나 메서드로 추출하여 재사용합니다.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    # Before
    def calculate_area(length, width):
        area = length * width
        print(f"Area: {area}")
    
    def calculate_perimeter(length, width):
        perimeter = 2 * (length + width)
        print(f"Perimeter: {perimeter}")
    
    # After
    def print_result(message, value):
        print(f"{message}: {value}")
    
    def calculate_area(length, width):
        area = length * width
        print_result("Area", area)
    
    def calculate_perimeter(length, width):
        perimeter = 2 * (length + width)
        print_result("Perimeter", perimeter)
    
  • 긴 함수 나누기: 하나의 함수가 너무 많은 일을 하는 경우, 작은 함수로 나누어 가독성과 재사용성을 높입니다.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    
    # Before
    def process_data(data):
        # 데이터 정제
        cleaned_data = clean_data(data)
        # 데이터 분석
        results = analyze_data(cleaned_data)
        # 결과 출력
        print_results(results)
    
    # After
    def process_data(data):
        cleaned_data = clean_data(data)
        results = analyze_data(cleaned_data)
        print_results(results)
    
    def clean_data(data):
        # 데이터 정제 로직
        pass
    
    def analyze_data(cleaned_data):
        # 데이터 분석 로직
        pass
    
    def print_results(results):
        # 결과 출력 로직
        pass
    
  • 매직 넘버 제거: 코드 내의 숫자 값을 상수로 치환하여 의미를 명확히 합니다.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    # Before
    def calculate_circle_area(radius):
        return 3.14159 * radius * radius
    
    # After
    PI = 3.14159
    
    def calculate_circle_area(radius):
        return PI * radius * radius
    

4.2. 구조 개선 기법

  • 클래스 추출: 하나의 클래스가 너무 많은 책임을 지고 있는 경우, 새로운 클래스로 분리합니다.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    
    # Before
    class Employee:
        def __init__(self, name, age, salary):
            self.name = name
            self.age = age
            self.salary = salary
    
        def calculate_pay(self):
            # 급여 계산 로직
            pass
    
        def save_to_database(self):
            # 데이터베이스 저장 로직
            pass
    
    # After
    class Employee:
        def __init__(self, name, age, salary):
            self.name = name
            self.age = age
            self.salary = salary
    
        def calculate_pay(self):
            # 급여 계산 로직
            pass
    
    class EmployeeRepository:
        def save_to_database(self, employee):
            # 데이터베이스 저장 로직
            pass
    
  • 메서드 이동: 메서드가 더 관련이 깊은 다른 클래스로 옮깁니다.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    
    # Before
    class Order:
        def __init__(self, order_id, customer):
            self.order_id = order_id
            self.customer = customer
    
        def get_customer_address(self):
            return self.customer.address
    
    class Customer:
        def __init__(self, customer_id, address):
            self.customer_id = customer_id
            self.address = address
    
    # After
    class Order:
        def __init__(self, order_id, customer):
            self.order_id = order_id
            self.customer = customer
    
        def get_customer_address(self):
            return self.customer.get_address()
    
    class Customer:
        def __init__(self, customer_id, address):
            self.customer_id = customer_id
            self.address = address
    
        def get_address(self):
            return self.address
    

결론

리팩토링은 소프트웨어 개발에서 지속적인 개선을 통해 코드 품질을 유지하고 향상시키는 중요한 과정입니다. 리팩토링의 원칙을 지키고, 다양한 기법을 적절히 활용하여 코드의 가독성, 유지보수성, 확장성을 높일 수 있습니다. 이를 통해 개발자는 더 효율적으로 작업할 수 있으며, 소프트웨어의 안정성과 성능을 향상시킬 수 있습니다.

다음시간에 계속…

image

This post is licensed under CC BY 4.0 by the author.