[Clean Code] Chapter 3. 함수

gahyun·2022년 2월 22일
0

(Feb. 21. 2022.) 3장 <함수>

기억하고 싶은 내용

  • 작게 만들어라!
    • 각 함수가 이야기 하나를 표현한다.
    • if 문/else 문/while 문 등에 들어가는 블록은 한 줄이어야 한다. 대개 거기서 함수를 호출한다. 그리고 함수에서 들여쓰기 수준은 1단이나 2단을 넘어가면 안된다.
  • 한 가지만 해라!
    • Do one thing, and do it well. (SRP)
    • 지정된 함수 이름 아래에서 추상화 수준이 하나인 단계만 수행.
    • 함수로부터 의미 있는 이름으로 다른 함수(작업)를 추출할 수 있다면, 그 함수는 여러 작업을 하는 셈이다.
  • 함수 당 추상화 수준은 하나로!
    • 함수 내 모든 문장의 추상화 수준이 동일해야 한다. 즉, 한 함수 내에 (서로 다른 여러 개의) 추상화 수준을 섞지 않도록 한다.
    • 코드는 위에서 아래로 이야기처럼 읽혀야 좋다.
  • switch 문
    • switch 문은 SRP, OCP 등을 위반하기 쉬워 주의해야 하는 구조다.
    • 일반적인 해결책은 인터페이스(추상화)와 다형성을 이용하고, switch 문은 (다형성 객체를 생성하는) 추상 팩토리에 꽁꽁 숨기는 것이다.
  • 서술적인 이름 사용
    • 이름은 길어도 괜찮다. 함수 이름을 정할 때는 여러 단어가 쉽게 읽히는 명명법을 사용한다.
    • 이름을 붙일 때는 일관성이 있어야 한다.
  • 함수 인수
    • 이상적인 인수 개수는 0개(무항)다. 다음은 1개(단항)고, 다음은 2개(이항)다.
    • 인수는 어렵다. 인수는 개념을 이해하기 어렵게 만든다. 테스트 관점에서 보면 인수는 더 어렵다. 출력 인수는 입력 인수보다 이해하기 어렵다.
    • 많이 쓰는 단항 형식
      • 인수에 질문을 던지는 경우
      • 인수를 뭔가로 변환해 결과를 반환하는 경우: 변환 결과는 반환값으로 돌려준다.
      • 이벤트 함수: 조심해서 사용할 것. 이벤트라는 사실에 코드에 명확히 드러나야 함.
    • 플래그 인수는 추하고 끔찍하다.
    • 이항 함수가 적절한 경우
      • 직교 좌표계의 x, y 값: 한 값을 표현하는 두 요소이며, 자연적인 순서도 있다.
    • 인수 객체 (객체로 된 인수)
      • double x, double yPoint center 로 묶기.
    • 인수 목록 (인수 개수가 가변적인 경우)
      • 가변 인수 전부를 동등하게 취급하면 List형 인수 하나로 취급 가능. 그렇게 따지면 사실상 가변 인수를 취하는 함수는 단항, 이항, 삼항 함수로 취급할 수 있다.
    • 동사와 키워드 (좋은 이름)
      • 좋은 함수/인수 이름: 단항 함수는 함수와 인수가 동사/명사 쌍을 이뤄야 한다.
      • 함수 이름에 인수 이름을 넣을 수도 있다.
  • 부수효과를 일으키지 마라!
    • 한 함수는 한 가지 일만 하게 하라 (SRP). 함수 이름에 드러나 있지 않은 일을 몰래 하게 하지 마라.
    • 일반적으로 출력 인수는 피해야 한다. OOP 언어에서는 출력 인수를 사용할 필요가 거의 없다. 출력 인수로 사용하라고 설계한 변수가 바로 this이기 때문.
  • 명령과 조회를 분리하라!
    • 함수는 뭔가를 수행하거나 (객체 상태를 변경하거나,) 뭔가에 답하거나 (객체 정보를 반환하거나) 둘 중 하나만 해야 한다. (SRP)
  • 오류 코드보다 예외를 사용하라!
    • 멀쩡한 Exception을 놔두고 왜 별도의 오류 코드를 만들어서 반환하는가?
    • try/catch 블록은 추하다. 별도 함수로 뽑아내서, 정상 동작과 오류 처리 동작을 분리하는 편이 좋다. 오류 처리도 '한 가지' 작업에 속한다. (SRP)
  • 반복하지 마라!
    • 중복은 문제다. 중복은 소프트웨어에서 모든 악의 근원이다.
  • 함수를 짜는 건 글짓기와 비슷하다. 초안을 쓴 다음, 서서히 다듬는다. 이 때, 코드를 빠짐없이 테스트하는 단위 테스트 케이스를 만들어서, 다듬는 와중에 코드가 항상 단위 테스트를 통과함을 확실히 한다.
  • 시스템을 '풀어갈 이야기'로 인식하자. 그 이야기를 풀어나가는 것이 함수 계층이다. 함수 계층은 시스템에서 발생하는 모든 동작을 설명한다. 따라서 함수가 분명하고 깔끔해야 이야기를 풀어가기가 쉬워진다.

소감

  • 이 장에서 소개된 가이드라인의 상당수는 SOLID의 일부 원칙이 잘 지켜질 수 있도록 돕는 방법들인 듯 하다. 좋은 코드는 가독성이 좋고 유지 보수가 쉬운 코드이며, 그걸 달성하기 위한 설계 원칙이 SOLID이므로 당연한 것인지도 모르겠다. 항상 SOLID 원칙을 준수하도록 주의를 기울이면 좋은 함수를 작성하는 데 도움이 되겠다.
  • 함수에서 이상적인 인수 개수는 0개인 점, 단항 함수도 꼭 필요한 (위에서 언급된 두 가지) 경우가 아니라면 가급적 피하라는 조언이 새로웠다. 단순한 원칙이니 머리에 새겨두고 자주 상기하면 좋겠다.
  • try/catch 블록을 쓸 때 실제 로직과 오류 처리 동작을 분리시키니, 상황을 이해하기가 훨씬 쉽고
    깔끔한 상태가 된다는 걸 깨달았다. 지금껏 이런 식으로 정리하지 않았다. 지금껏 싸질러놓고 지나온, 실제 동작과 오류 처리가 뒤섞인 수많은 try/catch 구문이 스쳐지나간다...
  • TDD의 중요성이 다시 언급되었다. 코드가 초안부터 완벽할 수는 없고 차근차근 리팩토링을 해야 하는데, 그 과정을 그나마 수월하게 거치기 위해 테스트코드는 필수적이란 거다.
    • 지금 작업 중인 회사 프로젝트에서 기존 코드에 쉽게 손댈 수 없는 이유가 바로 테스트코드가 전무해서다. 섣불리 건드렸다간 어디가 어떻게 망가질지 모르기 때문이다. 높은 code coverage를 갖는 테스트 케이스의 준비는 분명 개발 속도를 더디게 하는 부분이 있으므로 철저한 수준의 테스트코드를 기대하지 않았지만, 그렇다고 전혀 없는 건 좀 아니지 않나 싶다. 😭
  • 2장 <의미 있는 이름>을 읽고 이름이 과도하게 길어지면 어떡하나 하는 의문을 가졌었는데, 이 장에서 (함수) 이름은 길어져도 겁 먹을 필요 없다며 괜찮다고 확실하게 안심시켜 주고 있었다. 의문이 풀렸다.

궁금한 내용 / 잘 이해되지 않는 내용

  • '반복하지 마라!' 섹션에서는 왜 면도하는 삽화를 넣었을까?

0개의 댓글