클린 코드 | 03. 함수

yeonk·2023년 1월 9일
1

클린 코드

목록 보기
3/3
post-thumbnail

함수는 프로그램의 기본적인 단위이다.
함수를 잘 만드는 방법에 대해 알아보자.










작게 만들기


함수는 작게 만들어야 한다.
각 함수는 이야기 하나를 표현해야한다.

  • 블록과 들여쓰기
    • if 문, else문, while 문 등에 들어가는 블록은 한 줄이어야 한다.

      블록 안에서 호출하는 함수 이름을 적절하게 짓는다면 코드를 이해하기도 쉬워진다.
      중첩 구조가 생길만큼 함수가 커져서는 안된다.

    • 함수에서 들여쓰기 수준은 1단이나 2단을 넘어서면 안 된다.










한 가지 작업


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

  • 지정된 함수 이름 아래에서 추상화 수준이 하나인 단계만 수행한다면 그 함수는 한 가지 작업만 한다.

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

  • 한가지 작업만 하는 함수는 자연스럽게 섹션으로 나누기 어렵다.










추상화 수준


함수 당 추상화 수준은 하나여야 한다.

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

  • 한 함수 내에 추상화 수준을 섞으면 코드를 읽는 사람이 헷갈린다 (근본 개념과 세부사항이 뒤섞여 구분이 어려워짐).










내려가기 규칙


코드는 위에서 아래로 이야기처럼 읽혀야 좋다.
위에서 아래로 프로그램을 읽으면 함수 추상화 수준이 한 번에 한 단계씩 낮아진다.










Switch 문


가급적이면 switch 문은 사용하지 말자.

  • switch 문은 작게 만들기 어렵다.

  • 한 가지만 작업하는 switch 문도 만들기 어렵고, 본질적으로 switch문은 N가지를 처리한다.

  • switch 문을 사용해야한다면, 저차원 클래스에 숨기고 반복하지 않는 방법이 있다.










서술적인 이름


서술적인 이름을 사용해야 한다.
함수가 작고 단순할수록 서술적인 이름을 고르기도 쉬워진다.

  • 길고 서술적인 이름이 짧고 어려운 이름보다 좋다.

  • 길고 서술적인 이름이 길고 서술적인 주석보다 좋다.

  • 함수 이름을 정할 때는 여러 단어가 쉽게 읽히는 명명법을 사용한다.

  • 서술적인 이름을 사용하면 개발자 머릿속에서도 설계가 뚜렷해지므로 코드를 개선하기 쉬워진다.

  • 이름을 붙일 때는 일관성이 있어야 한다.










함수 인수


함수에서 이상적인 인수 개수는 0개이다. 다음은 1개, 2개이다.

  • 함수에서 3개의 인수는 가능한 피하는 편이 좋으며, 4개 이상은 특별한 이유가 필요하다.

  • 인수가 3개를 넘어가면 인수마다 유효한 값으로 모든 조합을 구성해 테스트하기가 상당히 부담스러워진다.

  • 인수 객체 - 인수가 2~3개 필요하다면 일부를 독자적인 클래스 변수로 선언할 가능성을 고려해야한다.

  • 인수 목록 - 가변 인수를 취하는 함수는 단항, 이항, 삼항 함수로 취급할 수 있다.










단항 함수(인수 1개)

  • 인수에 질문을 던지는 경우

  • 인수를 변환해 결과를 반환하는 경우

  • 이벤트 함수

    • 입력 인수만 존재하고 출력 인수는 없음

    • 시스템 상태를 바꿈

    • 이벤트라는 사실이 코드에 명확히 드러나야 함

  • 입력 인수를 변환하는 함수라면 변환 결과는 반환값으로 돌려준다.










플래그 인수(boolean)

  • 함수가 한번에 여러가지 일을 처리하는 것일 수 있다.

  • 플래그 인수는 좋지 못하다.










이항, 삼항 함수 (인수가 2, 2개)

  • 인수가 2개인 함수는 인수가 1개인 함수보다 이해하기 어렵다.

  • 이항 함수가 적절한 경우도 있다.
    좌표와 같이 인수 2개가 한 값을 표현하는 경우가 그 예이다.

  • 이항 함수가 무조건 나쁜 것은 아니지만 가급적 단항 함수로 바꾸도록 노력하는 것이 좋다.

  • 인수가 3개인 함수는 인수가 2개인 함수보다 더 이해하기 어렵다.










동사와 키워드

  • 함수의 의도나 인수의 순서와 의도를 제대로 표현하려면 좋은 함수 이름이 필수적이다.

  • 함수 이름에 키워드를 추가하는 형식을 사용해볼 수 있다.
    ex) assertExpectedEqualsActual(expected, actual)










부수 효과


부수 효과를 일으키지 말아야 한다.

많은 경우 시간적인 결합(temporal coupling)이나 순서 종속성(order dependecy)을 초래한다.

만약 시간적인 결합이 필요하다면 함수 이름에 분명히 명시한다.










출력 인수

  • 일반적으로 출력 인수는 피해야한다.

  • 함수에서 상태를 변경해야 한다면 함수가 속한 객체 상태를 변경하는 방식을 택한다.










명령과 조회


명령과 조회를 분리하라

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

  • 객체 상태를 변경하거나 객체 정보를 반환하거나 하나만 해야 한다.










예외


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

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

  • 오류 코드 대신 예외를 사용하면 오류 처리 코드가 원래 코드에서 분리되므로 코드가 깔끔해진다.










Try/Catch 블록 뽑아내기

  • try/catch 블록은 정상 동작과 오류 처리 동작을 뒤섞을 수 있기 때문에 블록을 별도 함수로 작성하는 것이 좋다.

  • 정상 동작과 오류 처리 동작을 분리하면 코드를 이해하고 수정하기 쉬워진다.










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

  • 오류를 처리하는 함수는 오류만 처리해야한다.










구조적 프로그래밍


  • 단일 입/출구 규칙

    • 모든 함수와 함수 내 모든 블록에 입구와 출구가 하나만 존재해야 한다.

    • 함수는 return문이 하나여야 한다.

    • 루프 안에서 break, continue를 사용해서는 안 되며 goto는 절대로 사용하지 않는다.

  • 하지만 함수를 작게 만든다면 return, break, continue를 여러 차례 사용해도 괜찮다.

2개의 댓글

comment-user-thumbnail
2023년 1월 10일

클린 코드는 여러번 봐도 반성하게 되는 것 같습니다
잘 보고 갑니다

1개의 답글