Community

개발자 99% 커뮤니티에서 수다 떨어요!

← Go back
TIL 3장. 함수
#clean_code
2년 전
451


TIL (Today I Learned)

2022.02.22

오늘 읽은 범위

3장. 함수

책에서 기억하고 싶은 내용을 써보세요.

<aside> 💡 함수의 의도를 명확히 표현해야 읽기 쉬워진다.

</aside>

  • 작게 만들어라 (p. 42)

    • 함수를 만드는 첫째 규칙은 작게!다.

    • 함수를 만드는 둘째 규칙은 더 작게!다.

    <aside> 💡 예전에 다른 책에서 함수는 딱 한 가지의 기능만 하게끔 작게 쪼개서 만들어라. 라는 말과 일맥상통하는 듯하다.

    </aside>

    • 바로 다음 글에 나오네!!

  • 한 가지만 해라 (p. 44)

    <aside> 💡 함수는 한 가지를 해야 한다. 그 한 가지를 잘 해야 한다. 그 한 가지만을 해야 한다.

    </aside>

    • 여기에 나오는 한 가지란?

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

    • 판단방법 1 : TO (~하려면) 문단 이용(책 예제 해설을 TO문단으로 해석하는 듯)

      <aside> 💡 TO RenderPageWithSetupsAndTeardowns, 페이지가 테스트 페이지인지 확인한 후 테스트 페이지라면 설정 페이지와 해제 페이지를 넣는다. 테스트 페이지든 아니든 페이지를 HTML로 렌더링한다.

      </aside>

    • 판단 방법 2 : 함수 내에서 의미있는 이름으로 다른 함수를 추출할 수 있다면 그 함수는 여러 작업을 하는 셈이다.

      • 그렇다면 그 함수를 다시 분해해서 한 가지 기능만 하도록 고쳐라.

  • 함수 당 추상화 수준은 하나로! (p.45)

    • 함수 내 모든 문장의 추상화 수준이 동일해야 한다.

    • 내려가기 규칙

      • 한 함수 다음에 나오는 함수는 추상화 수준이 한 단계 낮은 함수가 와야 한다. 즉 위에서 아래로 프로그램을 읽으면 함수 추상화 수준이 한 번에 한 단계씩 낮아진다.

  • Switch 문 (p. 47)

    • switch 문 자체가 여러 가지 일을 분기시켜 처리 하므로, 한 가지 작업만 하도록 만들기 어렵다. 하지만 switch 문을 저차원 클래스에 숨기고 절대로 반복하지 않는 방법이 있다. (다형성 - polymorphism -이용)

    • 필자도 이야기 했지만 뜻대로 되지 않는 경우가 많을 것이다. 개인적으로 최대한 switch 문을 피한다.

  • 서술적인 이름을 사용하라! (p. 49)

    • 이름을 정하느라 시간을 들여도 괜찮다. 이런저런 이름을 넣어 코드를 읽어보면 더 좋다. (최신 IDE에서 리펙토링이 쉬우므로 최대한 서술적인 이름을 골라라.)

    • 이름을 붙일 때는 일관성이 있어야 한다. 모듈 내에서 함수 이름은 같은 무누구, 명사, 동사를 사용한다.

  • 함수 인수 (p. 50)

    • 함수에서 이상적인 인수의 개수는 0개 이다. 그 다음은 1개이다. 3개 이상은 쓰지마라. 즉 적을 수록 좋다.

  • 부수 효과를 일으키지 마라! (p. 54)

    • 하나의 기능을 처리하는 함수에 다른 기능을 넣지 마라. 만약 꼭 필요하다면 함수 이름을 수정하여 부가적인 기능이 처리됨을 알려라.

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

      • appendFooter(report); → report.appendFooterr()

  • 명령과 조회를 분리하라! (p. 56)

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

      • 객체 상태를 변경하거나, 객체 정보를 반환하거나!

    • 애매모호한 형태의 함수를 사용하지 말 것

      • if (set(”username”, “unclebob”)) 은 username에 unclebob을 셋팅하라는 건지, username에 unclebob이 셋팅이 되어 있다면 인지 헷갈린다.

      • if (attributeExists(”username”)) { setAttribute(”username”, “unclebob”); ....} 처럼 명령과 조회를 분리하면 된다.

  • 오류 코드보다 예외를 사용하라! (p. 57)

    • try {} catch {} 구문을 사용하라. 단 별도의 함수로 만들어 정상 동작과 오류 처리 동작을 분리하라.

      public void delete(Page page) {
      	try {
      		deletePageAndAllReferences(page);
        }
      	catch (Exception e) {
      		logError(e);
      	}
      }
      
      private void deletePageAndAllReferences(Page page) throws Exception {
      	deletePage(page);
      	registry.deleteReference(page.name);
      	configKeys.deleteKey(page.name.makeKey());
      }
      
      private void logError(Exception e) {
      	logger.log(e.getMessage());
      }
      
    • 오류 코드 대신 예외를 사용하면 새 예외는 Exception 클래스에서 파생된다. 따라서 재컴파일/재배치 없이도 새 예외 클래스르 추가할 수 있다.

  • 반복(중복)하지 마라. (p. 60) - Don’t Repeat Yourself (DRY 법칙)

    • 중복은 소프트웨어에서 모든 악의 근원이다.

    • 소스코드에서 중복을 제거하려는 지속적인 노력을 기울여라.

  • 구조적 프로그래밍 (p. 61)

    • 꼭 필요한 경우가 아니라면 사용하지 말 것. 특히 goto

  • 그래서 함수를 어떻게 짜죠? (p. 61) - 지은이의 코딩 방법

    • 처음에는 길고 복잡하다. 중복된 루프도 많고, 인수 목록도 아주 길다. 이름은 즉흥적이고 코드는 중복된다. 하지만 단위 테스트 케이스는 모두 만든다.

    • 코드를 리펙토링 한다.

      • 이름을 바꾸고, 중복을 제거하고, 메서드도 줄이고 순서도 바꾼다.

      • 때로는 전체 클래스를 쪼개기도 한다.

      • 이 와중에도 코드는 항상 단위 테스트를 통과한다.

      • 최종적으로 이 장에서 설명한 규칙을 따르는 함수가 얻어진다.

      • 처음부터 탁 하고 튀어나오지는 않단다.

      • 그게 가능한 사람은 없으리라.

오늘 읽은 소감은? 떠오르는 생각을 가볍게 적어보세요

  • 다시금 강조되는 “코드는 이야기처럼 읽혀야 좋다.” 라는 것

  • 그나마 다행인 것은 함수는 대부분 한 가지 기능만 하도록 짜고 있다는 것이다. (그래도 그렇게 안 되는 것들도 많다는 것에 안타까움을 느깐다.) 다만 함수명이 통일되지 못하고, 인수가 조금 많은 경우가 있다는 것이다.

  • 변수명, 함수명, 클래스 명등 항상 이름 짓기가 많이 힘들다는 것을 느끼고 있고, 실무에서 항상 생각하며 바꿀 수 있도록 몇 번이고 읽어야 할 것 같다. 조금씩 고쳐 나가다 보면 언젠가는 제대로 된 코딩을 하고 있지 않을까?

궁금한 내용이 있거나, 잘 이해되지 않는 내용이 있다면 적어보세요.