[클린코드] 3장. 함수

노을·2022년 1월 27일
0

cleancode

목록 보기
3/8
post-thumbnail

작게 만들어라

  • 함수는 최대 네 줄


한가지만 해라

단순히 다른 표현이 아니라 의미 있는 이름으로 다른 함수를 추출할 수 있다면 그 함수는 여러 작업을 하는 셈이다. (p.45)

  • .getHtml()은 추상화 수준이 아주 높다.
    getHtml안에서는 그 코드가 하려는 작업을 위해서 여러가지 역할을 하는 코드들이 있을 것이기 때문

  • String pagePathName = PathParser.render(pagepath)는 추상화 수준이 중간
    PathParse.render라는 함수가 아마도 'pagepath에 해당하는 것'을 렌더링하는 역할을 하는 것이기 때문

  • .append(”\n”)는 추상화 수준이 아주 낮다.
    이 함수는 더이상 쪼갤 것이 없기 때문



Switch문은 다형성 이용

Switch문은 종류별로 어떤 일을 수행하는 것이기 때문에 길게 나올 수 밖에 없다.
다형성을 이용해 switch문을 추상화한다.

public Money calculatePay(Employee e)
        throws InvalidEmplᄋyeeType {
    switch (e.type) {
        case COMMISSIONED:
            return caleulateCommissionedPay(e);
        case HOURLY:
            return calculateHourlyPay(e);
        case SALARIED:
            return calculateSalariedPay(e);
        default:
            throw new InvalidEmployeeType(e.type);
    }
}

위 코드의 문제는

  • 함수가 길다
  • 한 가지 작업만 수행하지 않는다.
  • SPR(Single Responsibility Principle)을 위반한다. Employee 는 직원 유형 별로 여러가지 역할을 가지고 있다.
  • OCP(Open Closed Principle)을 위반한다. 새 직원 유형을 추가할 때 마다 그 직업 유형 페이를 구하는 메서드를 추가해야 하기 때문이다.


public abstract class Employee {
    public abstract boolean isPayday();
    public abstract Money calculatePay();
    public abstract void deliverPay(Money pay);
}

public interface EmployeeFactory {
    public Employee makeEmployee(EmployeeRecord r) throws InvalidEmployeeType;
}

public class EmployeeFactorylmpl implements EmployeeFactory {
    public Employee makeEmployee(EmployeeRecord r) throws InvalidEmployeeType {
        switch (r.type) {
            case COMMISSIONED:
                return new CommissionedEmployee(r);
            case HOURLY:
                return new HourlyEmployee(r);
            case SALARIED:
                ret니rn new SalariedEmployee(r);
            default:
                throw new InvalidEmp 'LoyeeType! r.type);
        }
    }
}
  • 추상클래스 Employee 를 상속 받는 자식 클래스들은 각각 calculatePay, isPayday, deliverPay 메서드를 오버라이드 한다.

  • 직원 유형에 따라 객체를 만들어 반환하고 그 객체로 메서드를 실행한다.

    → 메소드를 수정하지 않아도 되기 때문에 makeEmployee(EmployeeRecord r)를 똑같이 사용하면서 다양한 결과를 얻을 수 있다. (다형성)


서술적인 이름을 사용해라

길고 서술적인 이름이, 짧고 어려운 이름과 길고 서술적인 주석보다 좋다.


함수인수

  • 단항함수의 세가지 경우
    • 인수에 질문을 던지는 경우 boolean fileExists("MyFile")
    • 인수를 뭔가로 변환해 결과로 반환하는 경우 InputStream fileOpen("MyFile")
    • 이벤트 (입력 인수로 시스템 상태를 바꾸는 경우) void passwordAttemptFailedNtimes(int attempts)
  • 이항함수가 적절한 경우
    • 인수 두개가 하나의 값을 표현할때 Point p = new Point(0,0);
  • 인수 개수 해결 방법
    • 인수 개수가 많으면, 인수들을 포함하는 클래스를 만들어 객체 하나만 인수로 받는다. Circle makeCircle( double x, double y, double radius)Circle makeCircle( Point center, double radius)
    • 인수 클래스에 메서드를 구현 writeField(outputStream, name)outputStream.writeField(name)
    • 새 클래스를 만들어 생성자에서 outputStream 값을 받고 writeField(name)를 구현한다.. 객체를 만들어 writeField(name) 실행한다.
  • 플래그 인수 X
    render(boolean isSuite) → renderForSuite() & renderForSingleTest()
  • 키워드 추가
    순서가 모호하면 함수명에 인수 이름과 순서를 포함한다.
    assertEquals() → assertExpectedEqualsActual(expected, actual)


명령과 조회를 분리하라

함수는 뭔가를 수행(명령)하거나 뭔가에 답(조회)하거나이다.

//나쁜 예
if (set("username", "myname"))
  ...

//좋은 예
if (attributeExists("username")) {
  setAttribute("username", "myname");
  ...
}



오류코드보다 예외를 사용하라

  • 오류코드는 중첩된 if문을 야기한다.
  • try catch 블록을 별도 함수로 뽑아낸다. 진짜 수행하는 부분은 다른 곳에서 구현한다.



0개의 댓글