클린코드 3장 함수

노션에서 정리한 내용을 벨로그로 옮겼기 때문에 노션으로 보면 조금 더 보기 더 편합니다🤗

이동하기 → junnkk's Notion


함수를 읽기 쉽고 이해하기 쉽게 하는 방법. 의도를 분명히 표현하는 함수를 구현하는 방법. 처음 읽는 사람이 프로그램 내부를 직관적으로 파악할 수 있도록 하는 속성의 종류.

작게 만들어!

함수는 작을수록 좋다.

  • 블록과 들여쓰기

    if문 / else문 / while문 등에 들어가는 블록은 한 줄이어야 한다.

    → 바깥을 감싸는 함수(enclosing function)이 작아지고 블록 안에서 호출하는 함수 이름을 적절히 짓는 다면 코드를 이해하기 쉬워짐.

가지만 해라!

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

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

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

  • 함수 섹션

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


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

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

한 함수 내에 추상화 수준을 섞으면 코드를 읽는 사람이 헷갈린다.

∵ 특정 표현이 근본 개념인지 아니면 세부 사항인지 구분하기 힘들기 때문

  • 위에서 아래로 코드 읽기: 내려가기 규칙

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

    → 내려가기 규칙 : 위에서 아래로 프로그램을 읽으면 함수 추상화 수준이 한 번에 한 단계씩 낮아진다.


Switch 문

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

but 다형성을 이용하여 각 switch 문을 저차원 클래스에 숨기고 반복하지 않는 방법 사용하라

→ switch문을 추상 팩토리에 숨긴다.

예시) Employee and Factory (p48~49)

팩토리는 switc문을 사용해 적절한 employee 파생 클래스의 인스턴스 생성.

calculatePay, isPayday, deliverPay 등의 함수는 Employee 인터페이스를 커쳐 호출

⇒ 다형성으로 인해 실제 파생 클래스의 함수 실행

  • 저자는 다형적 객체를 생성하는 코드 안에서만 switch문 사용. 상속 관계로 숨긴 후 다른 코드에 노출 X

서술적인 이름을 사용하라!

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

  • 함수 이름을 정할 때는 여러 단어가 쉽게 읽히는 명명법 사용 후, 여러 단어를 사용해 기능 잘 표현하는 이름 선택

  • 일관성이 있어야 한다.

    →모듈 내에서 함수 이름은 같은 문구, 명사, 동사 사용


함수 인수

함수에서 이상적인 인수 개수 = 0개(무항) (1개(단항) → 2개(이항) → 3개(삼항) → 4개 이상(다항) 순)

  • 함수 인수로 넘기는 방법 대신 인스턴스 변수로 선언(3-7의 stringBuffer)
  • 테스트 관점에서 봤을 때 인수가 없으면 간단
  • 출력 인수는 입력 인수보다 이해하기 어렵

⇒ 최선은 인수가 없는 경우. 차선은 입력 인수가 1개인 경우.

  • 많이 쓰는 단항 형식

    • 함수에 인수 1개를 넘기는 이유

      1. 인수에 질문을 던지는 경우 ex) boolean fileExist("MyFile"
      2. 인수를 뭔가로 변환해 경과를 반환하는 경우 ex) InpuStream fileOpen("MyFile") : String 형의 파일 이름을 InpuStream으로 변환
    • 이벤트 (드물지만 유용한 단항 함수 형식)

      → 입력인수만 있음

      ⇒ 이외의 경우에는 단한 함수 피하라.

  • 플래그 인수

    플래그 인수 사용 X

  • 이항 함수

    Point p = new Point(0,0) 등을 제외하면 되도록 피하라.

  • 삼항 함수

    웬만하면 사용 X → 인수의 순서를 인위적으로 기억해야 하므로

  • 인수 객체

    객체를 생성해 인수를 줄인다.

  • 인수 목록

    인수 개수가 가변적인 함수 필요

    ex) String.Fomat

    ⇒ 사실은 이항 함수이다! public String format(String format, Object... args)

  • 동사와 키워드

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

    • 단항 함수 - 함수와 인수가 동사/명사 쌍 ex) writeField(name)

    • 함수 이름에 키워드 추가. 즉, 함수이름에 인수 이름 넣기

      ex) assertExpectedEqualsActual(expected, actual)


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

부수 효과 → 시간적 결함, 순서 종속성 초래

  • 출력 인수

    우리는 일반적으로 인수를 함수 입력으로 해석

    ∴ 일반적으로 출력 인수는 피해야 함. 함수에서 상태를 변경하야 한다면 함수가 속한 객체 상태를 변경하는 방식을 택해야함.

    • 객체 지향 언어에서는 출력 인수로 this 사용

명령과 조회를 분리하라!

함수는 뭔가를 수행(= 객체 상태 변경) or 뭔가에 답(= 객체 정보 반환)을 해야 함. → 둘 중 하나만!


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

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

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

  • Try/Catch 블록 뽑아내기

    try/catch 블록은 코드 구조에 혼란을 일으키므로 별도 함수로 뽑아내야 한다.

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

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

    오류를 처리하는 함수는 오류만 처리

  • Error.java 의존성 자석

    오류 코드를 반환한다 = 어디선가 오류 코드를 정의한다

    • 의존성 자석
        public enum Error {
        OK,
        INVAILD,
        NO_SUCH,
        LOCKED,
        OUT_OF_RESOURCES,
        WAITING_FOR_EVENT;
        }
        
오류 코드 대신 예외 사용 → 재컴파일/재배치 없이도 새 예외 클래스 추가 가능

반복하지 마라!

반복을 제거하려는 노력

ex) 자료에서 중복을 제거하기 위해 관계형 데이터베이스에 정규형 생성

ex) 객체 지향 프로그래밍은 코드를 부모 클래스로 몰아 중복 없앰.

ex) 구조적 프로그래밍, AOP, COP 등


구조적 프로그래밍

  • goto 문 사용 지양

함수를 어떻게 짜죠?

  1. 초안 작성
  2. 단위 테스트 케이스 생성
  3. 코드 다듬기, 함수 만들기, 이름 수정, 중복 제거, 메서드 줄이기, 순서 변경

결론


4장 주석

좋은 웹페이지 즐겨찾기