Chapter 3 - Functions

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

  • 함수: 가장 기본적인 코드 단위

작게 만들고 한 가지만 하기


  • if, else, while 등 블록에 들어가는 코드는 한줄
  • 중첩구조 지양
  • 직관적인 함수명을 활용하 것

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


  • 추상화 수준 1개만 보유하기
  • 함수 내 모든 문장의 추상화 수준이 동일
    • (HIGH) getHtml()
    • (MID) String pagePathName = PathParser.render(pageapth);
    • (LOW) .append("\n")
  • 함수 내 추상화 수준이 섞임 \(\rightarrow\) 읽을 때 헷갈림 (근본 개념 vs 세부사항 구분 어려움) \(\Rightarrow\) 세부사항이 더 추가됨 (broken window effect)

  • 위에서 아래로 코드 읽기
  • 내려가기 규칙: 위에서 아래로 함수 추상화 수준이 한번에 한 단계씩 낮아지기 \(\Rightarrow\) 추상화 수준 한 단계 유지 가능

Switch문

  • if, else 동일
  • 작게 만들기 어려움 (한 가지만 수행도 어려움)
  • SRP (Single Responsiblity Principle) 쉽게 위반 (코드를 변경할 이유가 여럿)
  • OCP (Open Closed Principle) 쉽게 위반 (유형 추가마다 코드 변경 필요)
  • 가장 문제점: 동일한 함수구조 여럿 존재
  • possible solution: ABSTRACT FACTORY (추상 팩토리)에 꽁꽁 숨기기

  • 책은 Java 기반이라 javascript 예시 (-ChatGPT)
    function createShape(type) {
      if (type === 'circle') {
        return createCircle();
      } else if (type === 'rectangle') {
        return createRectangle();
      } else if (type === 'triangle') {
        return createTriangle();
      } else {
        throw new Error('Invalid shape type');
      }
    }
    
    function createCircle() {
      return new Circle();
    }
    
    function createRectangle() {
      return new Rectangle();
    }
    
    function createTriangle() {
      return new Triangle();
    }
    const circle = createShape('circle');
    const rectangle = createShape('rectangle');
    const triangle = createShape('triangle');
    

서술적인 이름 사용


  • “코드를 읽으면서 짐작했던 기능을 각 루틴이 그대로 수행한다면 깨끗한 코드라 불러도 되곘다” - 워드
  • 함수가 작고 단순할수록 서술적인 이름 고르기 쉬움
  • 이름이 길어도 됨!! (주석보다 훨씬 낫다)
  • 모듈 내에서 함수명은 일관성 필요
    • 같은 문구, 명사, 동사 사용 (includeSetupAndTeardownPages, includeSetupPages, includeSuiteSetupPage..)

함수 인수


  • 이상적인 인수: 0개 (적을수록 좋음)
  • 4개 이상: 특별한 이유 필요
  • 테스트할 때도 인수는 적어야 쉽다
  • 출력 인수는 더 어렵다!

  • 명령과 조회를 분리하기!

  • 물론 불가피한 상황에는 룰들을 무시하는게 맞지만 최대한 지키려고 노력하기 (가독성 증가)

단항 형식

  1. 질문을 던질 떄 (fileExists('MyFile'))
  2. 변환 필요할 때 (InputStream fileOpen('MyFile')) (string -> InputStream으로 변경)
  3. 이벤트 함수
  • 이외에는 가급적 쓰지 말 것

플래그 인수

  • 굉장히 추하다 -Robert C. Martin
  • 부울 값 넘기는 것은 여러가지를 처리한다고 대놓고 공표하는 셈

이항 함수

  • 무조건적으로 나쁘지는 않지만, 위험은 따른다
  • 순서가 모호하다 check(expected, actual)
  • 불가피한 예시: point(x, y) \(\leftarrow\) 순서 명확

삼항 함수

  • 무조건 주춤한다. 개발자들이 각 인수가 무엇인지 찾아보게 된다

인수 객체, 목록

  • 인수가 많아질 경우 차라리 인수 객체가 낫다
  • 이름을 붙이므로 (Object Name) 결국에는 개념을 소개한다.

동사와 키워드

  • 단항 함수: 함수 - 인자가 동사-명사 쌍을 이루어야 함 (write ( name ), better: writeField( name ))
  • 키워드 추가: 함수 이름에 인수 이름 넣기 (asserEquals 보다 asserExpectedEqualsActual( expected, actual ))

부수 효과를 일으키지 마라


  • 부수효과 == 거짓말 (함수에 한가지 약속 뒤 남몰래 부수적으로 하는 행위)

  • can lead to 시간적인 결합 (temporal coupling) or 순서 종속성 (order dependency)

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


  • if중첩보다는 try-catch 문 사용
  • 사실 try-catch문도 분리하는게 좋음
  • 오류 코드들은 따로 정의하고 재사용 가능하게 하기

반복하지 마라


  • 중복은 SW에서 모든 악의 근원임
  • 데이터베이스 정규화, OOP, AOP (aspect), COP (component), 등 중복제거를 위한 지속적인 노력을 보임

구조적 프로그래밍


  • 모든 함수는 입구와 출구가 하나씩 -Dijkstra ( Typescript에서 early return은...?)
  • GOTO는 무조건적으로 피해야 한다

함수를 어떻게 짜야 하죠?


  • 글쓰기와 비슷하다. 처음부터 완벽하지는 않고 여러 단계를 거친다
  • 코드 작성 - 테스트 - 다듬기 - 함수 만들기 - 이름 변경 - 중복 제거 - 메서드 줄이기 - 순서 변경 - 클래스 쪼개기 - 단위 테스트…

결론


대가 (master) 프로그래머는 시스템을 (구현할) 프로그램이 아니라 (풀어갈) 이야기로 여긴다. 프로그래밍 언어라는 수단을 사용해 좀 더 풍부하고 좀 더 표현력이 강한 언어를 만들어 이야기를 풀어간다. 시스템에서 발생하는 모든 동작을 설명하는 함수 계층이 바로 그 언어에 속한다.


React로 프론트엔드 개발을 하고 있는데 props로 state값을 여럿 보내줘야 하는 경우가 대부분이다. 물론 상태관리 라이브러리를 사용하면 문제가 조금 줄지만 이마저도 업계에서는 지양하는 편이라고 했으니, 이런 경우에는 인자를 넘겨줘도 되는 것인가 이제부터 새로운 컴포넌트를 만들 때 고민할 것 같다…