ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Refactoring] 8장 : 기능 이동
    책/Refactoring 2판 2024. 2. 14. 11:32
    반응형

    함수 옮기기

    // before
    class SomeClass {
        get someFunc();
    }
    
    // after
    class AnotherClass {
        get someFunc();
    }
    • 이는 클래스 이름을 바꾼게 아니라 함수가 옮겨진 것이다.
    • 함수는 대부분 어떤 클래스에 속하게 된다. (자바의 경우 필수다)
    • 만약 어떤 함수가 자신이 속한 모듈 A보다 모듈 B의 요소를 더 참조한다면 모듈 B로 옮겨주는 것이다.

    필드 옮기기

    // before
    class Customer {
        get plan() {
            return this.plan;
        }
        get discountRate() {
            return this.discountRate;
        }
    }
    
    // after
    class Customer {
        get plan() {
            return this.plan;
        }
    
        get discountRate() {
            return this.plan.discountRate;
        }
    }
    • 위와 비슷하게, 함수에 어떤 레코드를 넘길 때마다 또 다른 레코드의 필드도 함께 넘기고 있다면 데이터 위치를 옮길 필요가 있다.
    • 서로 다른 레코드, 객체의 필드임에도 같이 움직여진다면, 한 곳으로 필드를 옮겨주는 것이다.

    문장을 함수로 옮기기

    // before
    print(info.title);
    printDetail(info);
    
    function printDetail(info) {
        print(info.content);
        print(info.writer);
    }
    
    // after
    printDetail(info);
    
    function printDetail(info) {
        print(info.tilte);
        print(info.content);
        print(info.writer);
    }
    • 특정 함수를 호출하는 코드가 나올 때마다 앞 혹은 뒤에서 똑같은 코드가 추가로 실행될 때, 반복 부분을 함수와 합치는 방법이다.

    문장을 호출한 곳으로 옮기기

    // before
    printDetail(info);
    
    function printDetail(info) {
        print(info.tilte);
        print(info.content);
        print(info.writer);
    }
    
    // after
    print(info.title);
    printDetail(info);
    
    function printDetail(info) {
        print(info.content);
        print(info.writer);
    }
    • 위와 반대로, 원래는 합쳐져 있는게 좋지만 요구사항이 바뀌어 따로 처리해줘야 하는 경우가 생길 수 있다.
    • 어느샌가 하나의 함수가 두가지 이상의 역할을 담당한다면, 달라진 동작 부분을 함수에서 꺼내 해당 호출자로 옮겨야 한다.

    인라인 코드를 함수 호출로 바꾸기

    // before
    let appliesToMess = false;
    for (const s of states) {
        if (s === "MA") appliesToMess = true;
    }
    
    // after
    appliesToMess = states.includes("MA");
    • 이미 존재하는 함수와 똑같은 일을 하는 인라인 코드를 발견했을 때, 이를 함수 호출로 바꿔주는 것이다.
    • 단, 정확히 일치하는지 확실히 알아야 한다. 이 때 중요한 것이 함수의 이름이다.
    • 이름은 반드시 동작 방식이 아닌 목적을 명시해줘야 한다.

    문장 슬라이드하기

    // before
    const div = a / b;
    const add = a + b;
    let sum;
    const sub = a - b;
    
    // after
    const div = a / b;
    const add = a + b;
    const sub = a - b;
    let sum;
    • 관련 코드끼리 모으는 작업을 말한다.
    • 이 때 참고할 점은 변수를 미리 선언하고 나중에 쓰는 방식 (C 언어 방식) 보다는 변수를 실제로 사용할 때 선언함과 동시에 초기화하는 것이 가장 좋다. (이펙티브 자바에서도 나온 얘기)

    반복문 쪼개기

    // before
    let answer = 0;
    let acc = 0;
    
    for (const n of numbers) {
        answer += n;
        acc += n;
    }
    
    // after
    let answer = 0;
    for (const n of numbers) {
        answer += n;
    }
    
    let acc = 0;
    for (const n of numbers) {
        acc += n;
    }
    • 함수 뿐만 아니라, 반복문에서도 두 가지 역할을 하는 것은 좋지 않다.
    • 물론 이 방식으로는 반복문을 두번 돌게 되므로 성능이 약간 느려지긴 할 것이다.
      • 하지만 리팩터링과 최적화는 다른 관점으로 봐야 할 것이고, 만약 정말 병목이라면 합치는 건 어렵지 않다.
    • 또한 이렇게 분리해 놓은 뒤에 함수 추출하기, 파이프라이닝하기 등으로 더 좋은 리팩토링이 가능해지므로 좋다.

    반복문을 파이프라인으로 바꾸기

    // before
    const names = [];
    
    for (const i of input) {
        if (i.job === "Programmer") {
            names.push(i.name);
        }
    }
    
    // after
    const names = input
                    .filter(i => i.job === "Programmer")
                    .map(i => i.name)
                    ;
    • 반복문의 경우 해당 반복문이 무엇을 하는지 코드를 자세히 확인해야 한다.
    • 이 때 파이프라인을 사용하면 각 논리 과정이 무엇을 의미하는지 한눈에 보인다.
    • 반복문은 가능하면 파이프라인으로 바꾸자.

    죽은 코드 제거하기

    • 전혀 사용하지 않는 코드, 필요없는 코드들을 주석처리하지 말자.
    • 대신 그냥 없애자.
    • 그럼 나중에 필요하면 어떻게? → 버전 관리 툴이 있다. (Git)

     

     

    https://product.kyobobook.co.kr/detail/S000001810241

    반응형
Designed by Tistory.