[클린코드] 함수 인수

Jake·2022년 2월 22일
0

책 읽기

목록 보기
2/5

함수 인수

함수에서 이상적인 인수 개수는 0개(무항)다.
다음은 1개(단항)고, 다음은 2개(이항)다. 3개(삼항)는 가능한 피하는 편이 좋다.
4개 이상(다항)은 특별한 이유가 필요하다. 특별한 이유가 있어도 사용하면 안 된다.
인수는 어렵다.
인수는 개념을 이해하기 어렵게 만든다.

  • 함수의 인수는 적을 수록 좋다
  • 앞에서 추상화 수준에 대해서 다뤘는데, 함수 이름과 인수 사이에도 추상화 수준이 같아야 한다.
  • 인수가 많을수록, 테스트 케이스를 작성하기 힘들다.

많이 쓰이는 단항 형식

  1. 인수에 질문을 던지는 경우

    → boolean fileExists(”MyFile”)

  2. 인수를 뭔가로 변환해 결과를 반환하는 경우

    → InputStream fileOpen(”MyFile”)

이들 두 경우는 독자가 당연하게 받아들인다. 함수 이름을 지을 때는 두 경우를 분명히 구분한다. 또한 언제나 일관적인 방식으로 두 형식을 사용한다.

  1. 이벤트 (입력 인수로 시스템 상태를 바꾸는 함수, 앞선 두 경우보다는 다소 드물게 사용한다)

    → passwordAttemptFailedNTimes(int attempts)

  • 이외의 케이스에서는 단항 함수는 가급적 피하도록 한다.

    언제나 일관적인 방식? 어느 정도로 일관적이어야 하는 것일까?

    다음 세 함수는 모두 같은 역할을 하는 함수입니다.

    1. StringBuffer transform(StringBuffer in)

      → in을 입력 인수로 받아 StringBuffer out을 반환합니다.

    2. void transform(StringBuffer out)

      → out을 변환하여 반환하는 함수입니다. 즉, out은 출력 인수입니다.

    3. StringBuffer transform(StringBuffer in)

      → in을 변환하여 반환하는 함수입니다. 즉, 입력 인수를 그대로 돌려주는 함수입니다.

    1번은 위에서 언급한 많이 쓰이는 단항 형식에 정확히 부합합니다.

    그렇다면, 2번과 3번 중에서는 어떤 형식을 취해야 할까요? 클린 코드에서는 이렇게 말합니다.

    입력 인수를 그대로 돌려주는 함수라 할지라도 변환 함수 형식을 따르는 편이 좋다.
    적어도 변환 형태는 유지하기 때문이다.

    → 3번이 차라리 낫다고 하네요!

플래그 인수

플래그 인수는 추하다. 함수로 부울 값을 넘기는 관례는 정말로 끔찍하다. 왜냐고? 함수가 한꺼번에 여러 가지를 처리한다고 대놓고 공표하는 셈이니까!

  • 괜히 찔리네요..ㅎ

이항 함수

  • 굳이 넣지 않아도 되는 인수는, 절대로 넣으면 안된다.
  • 물론 이항 함수가 적절한 경우도 있다. 일례로, 좌표계의 한 점을 표현하는 경우가 그렇다 Point p = new Point(0, 0)에서 인수 2개는 한 값을 표현하는 두 요소다. 이 경우는 이항 함수가 지극히 자연스럽다.

이항 함수가 무조건 나쁘다는 소리는 아니다. 프로그램을 짜다보면 불가피한 경우도 생긴다. 하지만 그만큼 위험이 따른다는 사실을 이해하고 가능하면 단항 함수로 바꾸도록 애써야 한다.

삼항 함수

  • 삼항 함수를 만들 때는 신중히 고려해야 한다.
  • 음험하지 않은 삼항 함수는, 주춤하게 될 가치가 있어야 한다.

assertEquals(1.0, amount, .001)은 그리 음험하지 않음 삼항 함수다. 여전히 주춤하게 되지만 그만한 가치가 충분하다. 부동소수점 비교가 상대적이라는 사실은 언제든 주지할 중요한 사항이다.

  • 이항 함수가 deprecated 되고, 삼항 함수가 권장되는 케이스가 있다?! → 클린 코드를 역행하는듯한 이 행위가, junit에서 실제로 일어났습니다. 어떤 케이스였을까요? 바로 위에서 언급한 부동소수점 비교에 대한 내용이었습니다. (참고 링크)
    • assertEquals(float expected,float actual) → deprecated

    • assertEquals(double expected,double actual,double delta) → replaced

      그만큼 주지할 만 한 중요 사항이었다는 뜻이겠죠? 이렇듯 인수는 적을 수록 좋다는 말이 무조건적으로 옳은 것은 아닙니다. 상황에 맞게 유연한 적용을 할 필요가 있겠습니다. 물론, 신.중.히. 고려해야겠지만요.

인수 객체

객체를 생성해 인수를 줄이는 방법이 눈속임이라 여겨질지 모르지만 그렇지 않다.
...(중략)
변수를 묶어 넘기려면 이름을 붙여야 하므로 결국은 개념을 표현하게 된다.

  • 개념을 표현한다는 말이 인상깊습니다. 함수는 읽고 이해하기 쉬워야 한다는 말과 일맥상통하는 것 같습니다. Circle makeCircle(double x, double y, doubel radius) 보다 Circle makeCircle(Point center, double radius) 가 훨씬 읽고 이해하기 쉽습니다.

인수 목록

  • 때로는 인수 개수가 가변적인 함수도 필요하다. String.format 처럼.
  • String.format은 사실상 이항 함수다. 가변 인수 전부를 동등하게 취급하면 List형 인수 하나와 같다.

동사와 키워드

  • write(name) < writeField(name)
  • assertEquals(expected, actual) < assertExpectedEqualsActual(expected, actual)
  • 함수 이름을 통해 함수의 의도나 인수의 순서와 의도를 정확히 전달하라.

부수 효과를 일으키지 마라!

부수 효과는 거짓말이다. 함수에서 한 가지를 하겠다고 약속하고선 남몰래 다른 짓도 하니까.

  • 부수 효과는 SRP를 위배하겠다는 말과 다름이 없다.

출력 인수

객체 지향 언어에서는 출력 인수를 사용할 필요가 거의 없다. 출력 인수로 사용하라고 설계한 변수가 바로 this이기 때문이다.

  • 출력 인수는 피해야 한다. 왜? 함수 선언부를 찾아보아야 이것이 출력 인수인지 아닌지를 알 수 있기 때문이다.
  • 함수에서 상태를 변경해야 한다면, 함수가 속한 객체 상태를 변경하는 방식을 택해야 한다.
profile
Java/Spring Back-End Developer

0개의 댓글