상세 컨텐츠

본문 제목

11. API 리팩터링

🍜개발자라면/책을 읽자✍

by :Eundms 2021. 11. 4. 10:59

본문

11.1 질의 함수와 변경 함수 분리하기

function getTotalOutstandingAndsendBill(){
   const result = customer.invoices.reduce((total,each)=>each.amount +total,0);
   sendBill();
   return result;
}

//질의 함수와 변경 함수 분리하기
function totalOutstanding(){
   return customer.invoices.reduce((total,each)=>each.amount +total,0);;
}
function sendBill(){
  emailGateway.send(formatBill(customer));
}
function alertForMiscreant(people){
    for(const p of people){
        if(p==='조커'){
            setOffAlarms();
            return '조커';
        }
        if(p==='사루만'){
            setOffAlarms();
            return '사루만';
        }
    }
    return '';
}
//========= 질의 함수와 변경 함수 분리하기
function findMiscreant(people){
    for(const p of people){
        if(p==='조커'){
            return '조커';
        }
        if(p==='사루만'){
            return '사루만';
        }
    }
    return '';
}
function alertFormiscreant(people){
    for(const p of people){
        if(p==='조커'){
            setOffAlarms();
            return ;
        }
        if(p==='사루만'){
            setOffAlarms();
            return;
        }
    }
    return;
}
const found = findMiscreant(people);
alertFormiscreant(people);

//======== findMiscreant랑 alertFormiscreant 의 중복된 코드 합치기
function alertForMiscreant(people){
    if(findMiscreant(people)!=="")setOffAlarms();
}

11.2 함수 매개변수화하기

function baseCharge(usage){
    if(usage<0)return usd(0);
    const amount = 
        bottomBand(usage)*0.03
        + middleBand(usage)*0.05
        + topBand(usage)*0.07;
    return usd(amount);
}
function bottomBand(usage){
    return Math.min(usage,100);
}
function middleBand(usage){
    return usage>100? Math.min(usage,200)-100:0;
}
function topBand(usage){
    return usage>200?usage-200:0;
}


//함수 매개변수화하기
function withinBand(usage,bottom,top){
    return usage>bottom?Math.min(usage,top)-bottom:0;
}
function baseCharge(usage){
    if(usage<0)return usd(0);
    const amount = 
        withinBand(usage,0,100)*0.03
        + withinBand(usage,100,200)*0.05
        + withinBand(usage,200,Infinity)*0.07;
    return usd(amount);
}

11.3 플래그 인수 제거하기

플래그 인수 : 함수 내에서 제어 흐름을 결정하는 데 사용해야 한다.

플래그 인수 없이 구현하려면 플래그 인수들의 가능한 조합 수 만큼의 함수를 만들어야 한다.

같은 로직을 조합해내는 더 간단한 함수를 만들 방법을 고민해야 한다.

불리언 값 : 호출자의 의도를 알 수 없음. 명시적인 함수를 사용해 호출자의 의도를 분명히 밝힐 것.

로직이 복잡해 명시적인 함수 자체를 만들기 까다롭다면, 래핑함수로 함수를 감싸라.

11.4 객체 통째로 넘기기

매개변수가 변해도 바꿀 필요가 없다.

11.5. 매개 변수를 질의 함수로 바꾸기 <=> 11.6. 질의 함수를 매개변수로 바꾸기

11.7. 세터 제거하기

세터 => 값 변경할 수 있다. 변경되어서는 안되는 값은 세터를 제거하자.

11.8. 생성자를 팩터리 함수로 바꾸기

생성자

1. 그 생성자를 정의한 클래스의 인스턴스를 반환해야 한다.- 서브 클래스의 인스턴스나 프락시를 반환할 수 없다.

2. 생성자 이름이 정해져 있다.

3. 특별한 연산자를 사용해야 해서 일반 함수가 오길 기대하는 자리에는 쓰기 어렵다.

11.9. 함수를 명령으로 바꾸기 <=> 11.10 명령을 함수로 바꾸기

명령 객체는 복잡한 연산을 다룰 수 있는 강력한 메커니즘을 제공한다.

명령 객체는 특정 함수를 위한 클래스를 만들고 그 함수와 연관된 함수나 변수를 클래스에 쪼개 넣어서

쪼개진 메서드들끼리 정보를 공유할 수 있도록 한다. 

만약, 로직이 복잡하지 않다면 평범한 함수로 바꿔주는 게 낫다.

 

명령을 함수롤 바꾸기 위해서는 보조 함수를 메인함수에 인라인하여 함수를 단일화 한다.

 

11.11. 수정된 값 반환하기

변수를 갱신하는 함수라면 수정된 값을 반환하여 호출자가 그 값을 변수에 담아두도록 하자.

function calculateAscent(){
    for (let i =1;i<points.length;i++){
        const verticalChange = points[i].elevation - points[i-1].elevation;
        totalAscent += (verticalChange>0) ? verticalChange : 0;
    }
}

calculateAscent안에서 totalAscent가 갱신된다는 사실이 드러나지 않으므로 calculateAscent()와 외부 환경이 어떻게 연결되는지가 숨겨진다.

 

11.12. 오류 코드를 예외로 바꾸기

예외(프로그램의 정상 동작 범주에 들지 않는 오류를 나타낼 때).

예외를 던지는 코드를 프로그램 종료 코드로 바꿔도 프로그램이 여전히 정상 동작할지를 따져보는 것이다. 정상 동작하지 않을 것 같다면 예외를 사용하지 말라는 신호이다. 

예외 대신 오류를 검출하여 프로그램을 정상 흐름으로 되돌리게끔 처리해야 한다.

11.13. 예외를 사전확인으로 바꾸기

미리 검사하자

관련글 더보기

댓글 영역