함수(2)

명령과 조회를 분리하라

책너두 5기 7일차

로버트 C. 마틴의 클린코드 p.57 ~ p.66

내용정리

명령과 조회를 분리하라!

함수는 뭔가를 수행하거나 답하거나 둘 중 하나만 해야한다.

public boolean set(String attribute, String value);

if (set("username", "unclebob"))... 대신

1
2
3
4
if (attributeExists("username")) {
    setAttribute("username", "unclebob");
    ...
}

로 명확하게 해서 혼란을 주지 말자.

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

오류 코드를 반환하면 명령/조회 분리 규칙이 위반된다.

if (deletePage(apage) == E_OK) 와 같은 형식은 피하자

1
2
3
4
5
6
7
8
try {
    deletePage(page);
    registry.deleteReference(page.name);
    configKeys.deleteKey(page.name.makeKey());
}
catech (Exception e) {
    logger.log(e.getMessage());
}

이처럼 예외를 사용하면 원래 코드에서 분리되어 깔끔해진다.

Try/Catch 블록 뽑아내기

Try/Catch 블록은 코드 구조에 혼란을 준다. 따라서 별도 함수로 뽑아내자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public void delete(Page page) {
    try {
        deletePageAndAllReferences(page);
    }
    catch (Exception e) {
        logError(e);
    }
}
private void deletePageAndAllReferences(Page page) throws Exception {
    deletePage(page);
    registry.deleteReference(page,name);
    configKeys.deleteKey(page.name.makeKey());
}

priva void logError(Exception e) {
    logger.log(e.getMessage());
}

이렇게 코드를 작성하면 delete함수는 모든 오류를 처리하여 이해하기 쉽다. 위와 같이 정상 동작과 오류 처리 동작을 분리해야 한다.

오류 처리도 한 가지 작업이다.

함수가 그렇듯, 오류 처리도 ‘한 가지’ 작업에 속한다. 따라서 함수에 키워드 try가 있다면 catch/finally문으로 끝나야 한다.

Error.java 의존성 자석

오류코드를 반환한다 = 클래스 or 열거형 변수 등 어디선가 오류코드를 정의함

1
2
3
4
5
6
7
8
public enum Error {
    OK,
    INVALID,
    NO_SUCH,
    LCOKED,
    OUT_OF_RESOURCES,
    WATTING_FOR_EVENT;
}

이 클래스는 의존성 자석(magnet)이라 다른 클래스에서 import하여 사용해야 한다. 수정하거나 추가하면 재컴파일 하고 재배치 해야한다. 오류 코드 대신 예외를 사용하면 재컴파일이 필요없다.

반복하지 마라!

include를 통해서건, 부모 클래스를 이용하건 중복은 무조건 없애야한다.

구조적 프로그래밍

함수가 작을떈 return, break, continue가 여러 차례 쓰여도 괜찮다. goto는 안된다.

클 떄는 출구가 하나여야 한다. return문이 하나여야한다. break,continue를 사용해선 안되고 goto절대 안된다.

함수를 어떻게 짜죠?

글쓰기와 마찬가지로, 처음에는 길고 복잡하고 더럽다. 그 이후 과정에서 다듬고, 함수를 만들고, 이름을 바꾸고, 중복을 제거한다. 메서드를 줄이고 순서도 바꾸고, 전체 클래스를 쪼개야 한다. 매 과정마다 단위 테스트를 통과해야 한다.

처음부터 깔끔하고 보기 좋은 코드를 짜는 것은 불가능하다.

결론

이 장에서 배운 함수를 잘 만드는 것은 ‘전체 시스템’이라는 이야기를 잘 풀어가기 위한 것이다.

읽고 나서

이번 부분에선 return문이 여러개라던가, continue 같은 것을 내가 자주 써서 많이 찔리(?)는 느낌이었다. 하지만 나는 아직 알고리즘 푸는 정도의 작은 코드에서만 사용해서 괜찮다고는 하는데.. 직므부터 습관을 들여놓지 않으면 나중에 큰 단위에서는 문제가 생길테니 잘 버릇을 들여놓자. 그리고 마지막에 한번에 완벽한 코드는 나오지 않는다고 하는 말이 인상깊었다. 정답을 맞추든, 기능을 하든 내가 쓴 코드를 다시 한번 보면서 정리하고 다듬어야겠다.