개요

적합한 데이터 구조를 활용하면 동작 코드는 자연스럽게 단순하고 직관적으로 짜여진다.

데이터 구조를 잘못 선택하면 데이터를 다루기 위한 코드로 범벅이 된다. 결국 이해하기 힘든 코드가 된다.

 

현재 데이터 구조가 적절치 않으면 바로 수정해야 한다.

 

함수에 어떤 레코드를 넘길 때마다 다른 레코드의 필드도 함께 넘기고 있다면, 필드 옮기기가 필요하다.

레코드의 변경을 때마다 다른 레코드의 필드까지 변경해야 한다면, 필드 옮기기가 필요하다.

여러 레코드에 정의된 똑같은 필드가 있을 레코드의 필드가 갱신될 다른 레코드 필드도 갱신해야 한다면 필드 옮기기가 필요하다.

 

필드 옮기기는 대체로 리펙터링을 위한 사전 작업인 경우가 많다.

 

레코드 뿐만 아니라 클래스도 똑같다. 데이터에 함수가 해진 레코드가 클래스이기 때문이다.

 

클래스는 접근자 메서드로 캡슐화가 되어 있어 비교적 리팩터링이 쉽다.

캡슐화되자 않은 날레코드는 훨씬 까다롭다.



//날레코드 예시,게터세터 없이 데이터를 직접 접근
public class RawRecord{
    public String data;
    public Integer data2;
}

예시



class Customer{
    constructor(name, discountRate){
        this._name = name;
        this._discountRate = discountRate;
        this._contract = new CustomerContract(dateToday());
    }
    get discountRate(){return this._discountRate;}
    becomePreferred(){
        this._discountRate += 0.03;
        //코드들 ...
    }
    applyDiscount(amount){
        return amount.subtract(amount.multiply(this._discountRate));
    }
}
class CustomerContract{
    constructor(startDate){
        this._startDate = startDate;
    }
}
Customer 클래스에 discountRate 변수를 CustomerContract 옮기고 싶다.
세터는 만들고 싶이 않아 메서드를 사용
class Customer{
    constructor(name, discountRate){
        this._name = name;
        this._setDiscountRate(discountRate);
        this._contract = new CustomerContract(dateToday());
    }
    get discountRate(){return this._discountRate;}
    //먼저 변수 캡슐화부터
    _setDiscountRate(aNumber){this._discountRate = aNumber;}
    becomePreferred(){
        this._setDiscountRate(this._discountRate +0.03);
        //코드들 ...
    }
    applyDiscount(amount){
        return amount.subtract(amount.multiply(this._discountRate));
    }
}


}
//필드와 접근자 추가
class CustomerContract{
    constructor(startDate,discountRate){
        this._startDate = startDate;
        this._discountRate = discountRate;
    }
    get discountRate(){return this._discountRate;}
    set discountRate(arg){this._discountRate = arg;}
}


class Customer{
    //계약 인스턴스를 사용하도록 수정
    constructor(name, discountRate){
        this._name = name;
        this._contract = new CustomerContract(dateToday());
        this._setDiscountRate(discountRate);
    }
    get discountRate(){return this._contract.discountRate;}
    _setDiscountRate(aNumber){this._contract.discountRate = aNumber;}
    becomePreferred(){
        this._setDiscountRate(this._discountRate +0.03);
        //코드들 ...
    }
    applyDiscount(amount){
        return amount.subtract(amount.multiply(this._discountRate));
    }
}
class CustomerContract{
    constructor(startDate,discountRate){
        this._startDate = startDate;
        this._discountRate = discountRate;
    }
    get discountRate(){return this._discountRate;}
    set discountRate(arg){this._discountRate = arg;}
}

리팩터링은 객체를 활용할 수월하다.

캡슐화 덕분에 데이터 접근이 메서드로도 메끄럽다.

함수로는 까다롭다.

 

예시: 공유 객체로 이동하기

이자율을 계좌 별로 설정하는 예시



class Account{
    constructor(number, type, interestRate){
        this._number = number;
        this._type = type;
        this._interestRate = interestRate;
    }
    get interestRate(){return this._interestRate;}
}
class AccountType{
    constructor(nameString){
        this.name = nameString;
    }
}
계좌 종류에 따라 정해지도록 수정


//interestRate 이자율 필드 생성 및 접근자 추가
class AccountType{
    constructor(nameString, interestRate){
        this._name = nameString;
        this._interestRate = interestRate;
    }
    get interestRate(){return this._interestRate;}
}
Acount AcountType 이자율을 가져오도록 수정하면 문제가 생길 있다.
전엔 Acount별로 자신만의 이자율을 가졌다. 지금은 같은 종류 계좌끼리 이자율을 공유하려 한다.
정말로 같은 종류 계좌는 이자율이 같은지가 관건이다. 반약 다르다면 리팩터링의 핵심인 "수정 전과 수정 겉보기 동작이 같아야 한다" 깨져 이상 리팩터링이 아니게 된다.
이를 위해 먼저 DB에서 같은 종류 계좌가 같은 이자율 같은지 검증하는 것이 필요하다. 그리고 어셔션을 추가하면 도움된다.


class Account{
    constructor(number, type, interestRate){
        this._number = number;
        this._type = type;
        //어셔션 추가한 상태로 당분간 운영하기
        assert(interestRate === this._type.interestRate);
        this._interestRate = interestRate;
    }
    get interestRate(){return this._interestRate;}
}


class Account{
    constructor(number, type, interestRate){
        this._number = number;
        this._type = type;
    }
    get interestRate(){return this._type.interestRate;}
}
class AccountType{
    constructor(nameString, interestRate){
        this._name = nameString;
        this._interestRate = interestRate;
    }
    get interestRate(){return this._interestRate;}
}

 

 

 

 

 

 

+ Recent posts