Clean Code 3-4 장

Park Jae Hong·2023년 5월 29일
0

함수

작게 만들어라

: 함수는 무조건 작게 만드는게 좋다.

  • if/else/while 문에 들어가느 블록은 한 중이여야 한다.
    (중첩 구조가 생길만큼 함수가 커져서는 안된다는 뜻.)

  • 함수의 들여쓰기는 1단이나 2단을 넘어서면 안된다.

한가지만 해라!

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

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

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

  • 위에서 아래로 코드 읽기: 내려가기 규칙
    : 코드는 위에서 아래로 이야기처럼 읽혀야 좋다. 한 함수 다음에는 추상화 수준이 한 단계 낮은 함수가 온다. 즉 위에서 아에로 프로그램을 읽으면 함수 추상화 수준이 한번에 한 단계씩 낮아지는 것.

Switch 문

: switch 문은 작게 만들기 어렵다. case 분기가 단 두개인 switch 문도 내 취향에는 너무 길며, 단일 블록이나 함수를 선호한다. 또한 한 가지 작업만 하는 switch 문도 만들기 어렵다. 본질적으로 switch 문은 N가지를 처리한다. 불행하게도 switch 문을 오나전히 피할 방법은 없다. 하지만 각 switch 문을 저차원 클래스에 숨기고 절대로 반복하지 않는 방법은 있다. 물론 다형성을 이용해야한다.48p

함수 인수

: 함수의 인수는 작으면 작을 수록 좋고 최대 3개정로 까지 사용해야한다. 인수가 많으면 코드를 이해하는데 힘들고, 테스트도 어려워 진다.

단항 형식

  • 인수에 질문을 던지는 경우 (ex-boolean fileExists("MyFile"))

  • 인수를 뭔가로 변환해 결과를 반환하는 경우 (ex-InputStream fileOpen("MyFlie"))

다소 드물게 사용하지만 그래도 아주 유용한 단항 함수 형식이 이벤트다. 이벤트 함수는 입력 인수만 있다. 출력 인수는 없다. 프로그램은 함수 호출을 이벤트로 해석해 입력 인수로 시스템 상태를 바꾼다. passwordAttemptFailedNtimes(int attempts) 가 좋은 예다. 이벤트 함수는 조심해서 사용한다. 이벤트라는 사실이 코드에 명확히 드러나야 한다. 그러므로 이름과 문맥을 주의해서 선택한다. 지금 까지 설명한 경우가 아니라면 단항 함수는 가급적 피한다. 예를 들어, void includeSetupPageInfo(StringBuffer pageText)는 피한다. 변환 함수에서 출력 인수를 사용하면 혼란을 일으킨다. 입력 인수를 변환하는 함수라면 변환 결과는 반환값으로 돌려준다. StringBuffer transform(StringBuffer in) 이 void transform(StringBuffer out) 보다 좋다. StringBuffer transform(StringBuffer in) 이 입력 인수를 그대로 돌려주는 함수라 할지라도 변환 함수 형식을 따르는 편이 좋다. 적어도 변환 형태는 유지하기 때문이다.

플래그 인수

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

이항 함수

  • 인수가 2개인 함수는 인수가 1개인 함수보다 이해하기 어렵다. 당연하다. 인수가 많을수록 해석해야하는 정보가 많아질테니.

  • Point의 경우는 직교 좌표계 점은 일반적으로 2개의 인수를 가지기때문에 적합하다.

  • 이항 함수가 무조건 나쁘다는 소리는 아니다. 프로그램을 짜다보면 불가피한 경우도 생긴다. 하지만 그만큼 위럼이 따른다는 사실을 인지하고 있어야한다.

삼항 함수

: 인수가 3개인 함수는 인수가 2개인 함수보다 훨씬 더 이해하기 어렵다. 순서, 주춤, 무시로 야기되는 문제가 두 배 이상 늘어난다. 그래서 삼항 함수를 만들 때는 신중히 고려하라 권고한다.

부수 효과를 일으키지 마라

: 부수 효과는 거짓말이다. 함수에서 한 가지를 하겠다고 약속하고선 남몰래 다른 것도 하니까 때로는 예사치 못하게 클래스 변수를 수정한다. 때로는 함수로 넘어온 인수나 시스템 전역 변수를 수정한다. 어느 쪽이든 교활하고 해로운 거짓말이다. 많은 경우 시간적인 결합이나 순서 종속성을 초해한다.

명령과 조회를 분히하라.

: 함수는 뭔가를 수행하거나 뭔가에 답하거나 둘 중 하나만 해야한다. 객체 상태를 변경하거나 아니면 객체 정보를 반환하거나 둘 중 하나다. 둘다하면 혼란을 초래한다.

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

: 명령 함수에서 오류 코드를 반환하는 방식은 명령/조회 분리 규칙을 미묘하게 위반한다. 자칫하면 if 문에서 명령을 표현식으로 사용하기 쉬운 탓이다.

반복하지 마라

: 코드 길이가 늘어날 뿐 아니라 알고리즘이 변하면 네 곳이나 수정해야한다. 게다가 어느 한곳이라도 빠뜨리는 경우 오류 발생할 확률도 네 배나 높다.

구조적 프로그래밍

: 어떤 프로그래머는 에츠허르 데이크스트라의 구조적 프로그래밍 원칙을 따른다. 데이크스트라는 모든 함수와 함수 내 모든 블록에 입구와 출구가 하나만 존재해야 한다고 말했다. 즉 함수는 return 문이 하나여야 한다. (루프 안에서 break나 continue를 사용해선 안되며 goto는 절대로 안된다. (when 문은 ?)

함수를 어떻게 짜죠 ?

: 소프트웨어를 짜는 행위는 여느 글짓기와 비슷하다. 논문이나 기사를 작성할 때는 먼저 생각을 기록한 후 읽기 좋게 다듬는다. 초안은 대개 서투르고 어수선하므로 원하는 대로 읽힐 때까지 말을 다듬고 문장을 고치고 문단을 정리한다.

결론

: 모든 시스템은 특정 응용 분야 시스템을 기술할 목적으로 프로그래머가 설계한 도메인 특화 언어로 만들어진다. 함수는 그 언어에서 동사며, 클래스는 명사다. 요구사항 문서에 나오는 명사와 동사를 클래스와 함수 후보를 고려한다는 끔찍한 옛 규칙으로 역행하자는 이야기가 아니다. 아니, 이것은 오히려 훨씬 더 오래된 진실이다. 프로그래밍의 기술은 언제나 언어 설계의 기술이다. 예전에도 그랬고 지금도 마찬가지다. 대가 프로그래머는 시스템을 프로그램이 아니라 이야기로 여긴다. 프로그래밍 언어라는 수단을 사용해 좀 더 풍푸하고 좀 더 표현역이 강한 언어를 만들어 이야기를 풀어간다. 시스템에서 발생하는 모든 동작을 설명하는 함수 계층이 바로 그 언어에 속한다. 재귀라는 기교로 각 동작은 바로 그 도메인에 특화된 언어를 사용해 자신만의 이야기를 풀어간다.

주석

: 잘 달린 주석은 그 어떤 정보보다 유용하다. 경솔하고 근거 없는 주석은 코드를 이해하기 어렵게 만든다. 오래되고 조잡한 주석은 거짓과 잘못된 정보를 퍼뜨려해아글 미친다. 주석은 쉰들러 리스트가 아니다. 주석은 순수하게 선하지 못하다. 사살상 주석은 기껏해야 필요악이다. 프로그래밍 언어 자체가 표현력이 풍부하다면, 아니 우리에게 프로그래밍 언어를 치밀하게 사용해 의도를 표현할 능력이 있다면 주석은 거의 필요하지 않으리라. 아니 전혀 필요하지 않으리라.

주석은 나쁜 코드를 보완하지 못한다.

: 코드에 주석을 추가하는 일반적인 이유는 코드 품질이 나쁘기 때문이다. 모듈을 짜고 보니 짜임새가 엉망이고 알아먹기 어렵다. 지저분한 모듈이라는 사실을 자각한다. 그래서 자신에게 이렇게 말한다. 이런 주석을 달아야겠다 아니다 코드를 정리해야 한다.

코드로 의도를 표현하라

: 확실히 코드만으로 의도를 설명하기 어려운 경우가 존재한다. 불행히도 많은 개발자가 이를 코드는 훌륭한 수단이 아니라는 의미로 해석한다. 분명히 잘못된 생각이다. 다음 코드 예제 두개를 살펴보자. 어느 쪽이 더 나은가 ?

좋은 주석

: 어떤 주석은 필요하거나 유익하다. 지금부터 글자 값을 한다고 생각하는 주서 몇 가지를 소개한다. 하지만 명심하기 바란다. 정말로 좋은 주석은 주석을 달지 않을 방법을 찾아낸 주석이라는 사실을 !

  • 법적인 주석
    : 때로는 회사가 정립한 구현 표준에 맞춰 법적인 이유로 특정 주석을 넣으라고 명시한다. 예를 들어, 각 소스 파일 첫머리에 주석으로 들어가는 저작권 정보와 소유권 정보는 필요하고도 타당하다.

  • 정보를 제공하는 주석
    : 때로는 기본적인 정보를 주석으로 제공하면 편리하다. 예를 들어, 다음 주석은 추상 메서드가 반환할 값을 설명한다.

  • 의도를 설명하는 주석
    : 때떄로 주석은 구현을 이해하게 도와주는 선을 넘어 결정에 깔린 의도까지 설명한다.

  • 의미를 명료하게 밝히는 주석
    : 때때로 모호한 인수나 반환값은 그 의미를 읽기 좋게 표현하면 이해하기 쉬워진다. 일반적으로는 인수나 반환값 자체를 명확하게 만들면 더 좋겠지만, 인수나 반환값이 표준 라이브러리나 변경하지 못하는 코드에 속한다면 의미를 명료하게 밝히는 주석이 유용하다.

  • 결과를 경고하는 주석
    : 때로 다른 프로그래머에게 결과를 경고할 목적으로 주석을 사용한다. 예를 들어, 다음은 특정 테스트 케이스를 꺼야 하는 이유를 설명하는 주석이다.

  • TODO 주석
    : 때로는 앞으로 할 일을 //TODO 주석으로 남겨두면 편하다. 다음은 함수를 구현하지 않은 이유와 미래 모습을 //TODO 주석으로 설명한 예제다.

나쁜 주석

: 대다수 주석이 이 범주에 속한다. 일반적으로 대다수 주성은 허술한 코드를 지탱하거나, 엉성한 코드를 변명하거나, 미숙한 결정을 합리화하는 등 프로그래머가 주정거리는 독백에서 크게 벗어나지 못한다.

  • 주절거리는 주석
    : 특별한 이유 없이 의무감으로 혹은 프로세스에서 하라고 하니까 마지못해 주석을 단다면 전적으로 시간낭비다. 주석을 달기로 결정했다면 충분한 시간을 들려 최고의 주석을 달도록 노력한다.

  • 같은 이야기를 중복하는 주석

  • 오해할 여지가 있는 주석
    : 때때로 의도는 좋았으나 프로그래머가 딱 맞을 정도로 엄밀하게는 주석을 달지 못하기도 한다.

  • 의무적으로 다는 주석
    : 모든 함수에 javadocs를 달거나 모든 변수에 주석을 달아야한다는 규칙은 어리석기 그지없다.

  • 있으나 마나한 주석
    : 때때로 있으나 마나 한 주석을 접한다. 쉽게 말해, 너무 당연한 사실을 언급하며 새로운 정보를 제공하지 못하는 주석이다.

  • 무서운 잡음
    : 때로는 javadocs도 잡음이다. 다음은 잘 알려진 오픈소스 라이브러

  • 함수나 변수로 표현할 수 있다면 주석을 달지 마라

  • 위치를 표시하는 주석

  • 닫는 괄호에 다는 주석
    ex - 함수가 복잡해져 while,if 문 등 닫는 괄호 뒤에 while,if를 표시하는 주석

  • 주석으로 처리한 코드

  • HTML 주석

  • 전역 정보
    : 주석을 달아야 한다면 근처에 있는 코드만 기술하라.

모호한 관계

: 주석과 주석이 설명하는 코드는 둘 사이 관계가 명백해야 한다.

함수 헤더

: 짧은 함수는 긴 설명이 필요 없다. 짧고 한가지만 수행하며 이름을 잘 붙인 함수가 주석으로 헤더를 추가한 함수보다 훨씬 좋다.

비공개 코드의 javadocs

: 공개 코드의 javadocs가 유용하지만 공개하지 않을 코드라면 쓸모없다.;

profile
The people who are crazy enough to think they can change the world are the ones who do. -Steve Jobs-

0개의 댓글