리팩터링/리팩터링 기법

리팩터링 기법. 단계 쪼개기(Split Phase)

developer-tj 2023. 3. 18. 12:00
반응형

단계 쪼개기(Split Phase)는 복잡한 작업이 하나의 함수 안에서 이뤄지는 경우, 작업을 단계별로 분리하여 별도의 함수로 추출하는 리팩터링 기법입니다.
이를 통해 기능이 구현되는 방식을 단순화하고, 변경이 필요한 경우 관련된 코드만 수정할 수 있게 됩니다.

예를 들어, 데이터베이스에서 정보를 읽어와 필요한 가공 작업을 수행하는 함수가 있다고 가정해 봅시다.
이 함수 안에는 데이터베이스 연결, 쿼리 실행, 결과 처리 등 많은 작업이 들어갈 수 있습니다.
이렇게 작업이 복잡해지면 코드를 수정하기 어렵고, 오류가 발생하기 쉬워집니다.

이 경우 단계 쪼개기를 적용하여 코드를 리팩터링할 수 있습니다.
예를 들어, 데이터베이스 연결과 쿼리 실행을 담당하는 함수와 결과 처리를 담당하는 함수를 분리하여 구현할 수 있습니다.
이렇게 하면 함수 각각이 단순해지고, 필요한 경우 각 함수를 수정하면 되므로 유지 보수가 용이해집니다.

단계 쪼개기는 함수 옮기기, 함수 추출하기 등 다른 리팩토링 기법들과 결합하여 사용할 수 있습니다.
단계 쪼개기를 통해 작업 단계를 분리하고, 함수 옮기기를 통해 작업을 관리하기 쉬운 위치로 이동시키고, 함수 추출하기를 통해 기능을 단순화하면서 코드의 가독성과 유지 보수성을 높일 수 있습니다.


다음은 학생들의 이름과 성적이 담긴 std::vector를 입력으로 받아, 성적순으로 정렬한 후 순위를 매기는 함수 rankStudents()입니다. 이 함수에서는 Divergent Change 문제가 발생합니다.


#include <iostream>
#include <vector>
#include <algorithm>

struct Student {
    std::string name;
    double grade;
};

void rankStudents(std::vector& students) {
    // 성적순으로 정렬
    std::sort(students.begin(), students.end(),
              [](const Student& a, const Student& b) { return a.grade > b.grade; });

    // 순위 매기기
    int rank = 1;
    for (int i = 0; i < students.size(); i++) {
        std::cout << rank << ". " << students[i].name << " (" << students[i].grade << ")" << std::endl;
        if (i < students.size() - 1 && students[i].grade > students[i+1].grade) {
            rank++;
        }
    }
}

위 코드에서 rankStudents() 함수는 두 가지 일을 수행하고 있습니다.

  1. 입력으로 받은 학생들의 성적을 내림차순으로 정렬합니다.
  2. 그 결과를 바탕으로 순위를 매깁니다.

이 문제를 단계 쪼기기를 적용하면, rankStudents() 함수에서는 성적순으로 정렬하는 것만 수행하고, 실제 순위를 매기는 함수 rankStudentsByGrade()를 별도로 구현하면 됩니다.


void rankStudentsByGrade(std::vector& students) {
    int rank = 1;
    for (int i = 0; i < students.size(); i++) {
        std::cout << rank << ". " << students[i].name << " (" << students[i].grade << ")" << std::endl;
        if (i < students.size() - 1 && students[i].grade > students[i+1].grade) {
            rank++;
        }
    }
}

void rankStudents(std::vector& students) {
    std::sort(students.begin(), students.end(),
              [](const Student& a, const Student& b) { return a.grade > b.grade; });
    rankStudentsByGrade(students);
}

이렇게 함으로써 함수의 역할 별로 구분하여 함수 각각이 단순해지고, 가독성과 유지 보수성을 높일 수 있습니다.


단계 쪼개기와 함수 추출하기 차이점

단계 쪼개기와 함수 추출하기는 모두 코드를 더 작고 이해하기 쉽게 만들기 위한 리팩터링 기법입니다.
그러나 두 기법은 서로 목적과 사용 방법이 다릅니다.

단계 쪼개기는 일련의 연산을 두 개 이상의 단계로 분리하여 코드를 재구성하는 기법입니다.
이를 통해 코드의 각 부분이 명확하게 구분되고, 각 부분을 개별적으로 변경하거나 재사용할 수 있습니다.
예를 들어, 데이터 입력과 처리, 출력으로 구성된 함수가 있다면, 단계 쪼개기를 적용하여 데이터 입력과 처리 부분과 출력 부분을 분리할 수 있습니다.

함수 추출하기는 긴 함수를 작은 단위로 분해하고, 각 단위를 개별적으로 함수로 추출하는 기법입니다.
이를 통해 코드의 가독성을 높이고, 코드의 중복을 제거하며, 각 함수가 특정 목적을 수행하도록 구성할 수 있습니다.
예를 들어, 긴 함수가 있다면, 함수 추출하기를 적용하여 각 단계를 수행하는 함수를 추출할 수 있습니다.

따라서, 함수 추출하기는 연산을 단계별로 분리하여 코드를 재구성하는 기법이며, 함수 추출하기는 긴 함수를 작은 단위로 분해하여 함수로 추출하는 기법입니다.