본문 바로가기
공부 기록

[클린코드] 3장. 함수

by 매트(Mat) 2024. 4. 15.

3장. 함수

어떤 프로그램이든 가장 기본적인 단위가 함수다.

이해할 수 없는 함수

  • 추상화 수준이 다양하고, 코드가 길다.
  • 두 겹으로 중첩된 if 문은 이상한 플래그를 사용
    • 플래그는 사용하지 말아야 한다.

작게 만들어라

함수는 작을수록 좋다.

참고로 전 회사에서는 한 메서드에 700줄이 넘었다. 메서드만 보고 너무 길어서 한숨부터 나왔던 기억이 있다. 이를 인터페이스를 활용하여 단 10줄 안으로 만들어서 뿌듯했던 기억이 있다.

한 가지만 해라

메서드 안에 기능을 여러 개 사용하는 것은 좋지 않다.

  • 함수는 한 가지를 해야 한다. 그 한 가지를 잘 해야 한다. 그 한 가지만을 해야 한다.

여기서 한 가지라는 건 추상화 수준이 하나인 단계만 수행하는 것을 말한다. 즉, 비슷한 기능 여러가지를 한 메서드 안에 작성한다면 그것은 한 가지 기능이 아닌 것이다.

함수 당 추상화 수준은 하나로

위에서 말했듯이 함수가 확실히 한 가지 작업만 하려면 함수 내 모든 문장의 추상화 수준이 동일해야 한다.

  • 코드는 위에서 아래로 이야기처럼 읽혀야 좋다.

Switch 문

  • 본질적으로 switch문은 N가지를 처리 한다. (한가지만 X)
  • 또한 코드가 길어진다.
  • SRP, OCP 위반

해결법은 다형성을 활용한 팩토리 패턴을 이용하는 것이다. 하지만 배보다 배꼽이 더 클지 고민을 해봐야 한다.

서술적인 이름을 사용하라

함수 이름은 함수가 하는 일을 좀 더 잘 표현할 수 있도록 짓는 것이 좋다. 좋은 이름이 주는 가치는 아무리 강조해도 지나치지 않다.

코드를 읽으면서 짐작했던 기능을 각 루틴이 그대로 수행한다면 깨끗한 코드라 불러도 되겠다.

함수 인수

함수에서 이상적인 인수 개수는 0개이다. 즉, 적을수록 좋고, 3개는 가능한 피하는 편이 좋고, 4개 이상은 특별한 이유가 필요하다. (아니, 특별한 이유가 있어도 사용하면 안된다!)

인수가 많을수록 해당 인수가 어떤 기능을 하는지 파악하는 시간이 길어진다. 또한 테스트 코드 작성도 부담스러워진다.

부수 효과를 일으키지 마라

예를 들면, 비밀번호 암호를 확인하는 메서드인 checkPassword()가 있다고 가정하자. 하지만 이 checkPassword() 메서드 안에 세션을 초기화하는 코드가 있다면 이는 부수 효과를 일으킨 것이다. 그 이유는 메서드명만 보면 단순히 암호를 확인하는 메서드지만 의도하지 않은 세션 초기화 로직이 들어 있는 것이다.

만약 암호를 확인하는 메서드를 재활용한다고 하면 의도하지 않은 세션 초기화 로직이 그대로 실행되는 불상사를 일으킨다.

명령과 조회를 분리하라

함수는 뭔가를 수행하거나 뭔가에 답하거나 둘 중 하나만 해야 한다. 즉, 객체 상태를 변경하거나 아니면 객체 정보를 반환하거나 둘 중 하나다.

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

명령 함수에서 오류 코드를 반환하는 방식은 명령/조회 분리 큐칙을 미묘하게 위반한다.

오류 코드를 사용하면 여러 단계로 중첩되는 코드를 야기하여 코드가 길어진다. 또한 오류 코드를 반환하면 호출자는 오류 코드를 곧바로 처리해야 한다는 문제가 생긴다.

대신에 예외를 사용하면 코드가 훨씬 깔끔해진다.

반복하지 마라

리팩토링에서 다루었지만 중복되는 코드는 최악이다. 중복을 제거함으로써 코드가 깔끔해지고, 다른 사람들끼리 서로 협업하는 입장에서 유지보수하기가 수월해진다.

구조적 프로그래밍

  • 함수는 return 문이 하나
  • 루프 안에서 break나 continue 사용해선 안된다.
    • 단, 작은 함수를 만든다면 사용 OK!
  • goto는 절대로 절대로 안된다.

함수를 어떻게 짜죠?

  • 처음에는 함수 짤 때 길고 복잡하다.
  • 들여쓰기 단계도 많고 중복된 루프도 많다.
  • 인수 목록도 아주 길다.
  • 이름은 즉흥적이고 코드는 중복된다.

하지만 그속에서 단위테스트를 작성한다. 그런 다음 코드를 다듬고, 함수를 만들고, 중복을 제거한다. 메서드를 줄이고 순서를 바꾼다. 때로는 전체 클래스를 쪼개기도 한다.

이와중에도 코드는 항상 단위테스트를 통과해야 한다.

정리하면 일단 기능이 돌아가게 작성 -> 단위테스트 작성 -> 리팩토링을 통한 코드 간결화 작업 -> 단위테스트 실행

References

댓글