클린 코드 책 커버 #노마드코더 #북클럽 #노개북

내용 요약(Notion)

TIL (Today I Learned)

함수를 깔끔하게 만드는 여러 규칙들에 대해 학습했다.

오늘 읽은 범위

3장. 함수

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

작게 만들어라!


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

한 가지만 해라!


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

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


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

switch 문


switch문은 작게 만들기 어렵지만 각 switch 문을 저차원 클래스에 숨기고 절대로 반복하지 않는 방법은 있다. 다형성(polymorphism)을 이용한다.

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


워드 커닝햄

“코드를 읽으면서 짐작했던 기능을 각 루틴이 그대로 수행한다면 깨끗한 코드라 불러도 되겠다”

함수 인수


함수에서 이상적인 인수 개수는 0개(무항)다.

다음은 1개(단항)고,

다음은 2개(이항)다.

3개(삼항)는 가능한 피하는 편이 좋다.

4개 이상(다항)은 특별한 이유가 필요하다. 특별한 이유가 있어도 사용하면 안된다.

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


public class UserVAlidator {
    private Cryptographer cryptographer;

    public boolean checkPassword(String userName, String password) {
        User user = UserGateway.findByName(userName);
        if (user != User.NULL) {
            String codedPhrase = user.getPhraseEncodedByPassword();
            String phrase = cryptographer.decrypt(codedPhrase, password);
            if ("Valid Password".equals(phrase)) {
                Session.initialize(); // 부수 효과
                return true;
            }
        }
        return false;
    }
}

위 코드는 사용자 이름과 암호를 확인하는 함수이다. 하지만 중간에 Session.initialize() 부분은 부수 효과를 발생시키는 부분이다. checkPassword라는 함수 이름만 보고 호출하는 사용자는 사용자를 인증하면서 의도치 않게 기존 세션 정보를 지워버릴 수도 있다.

이런 부수 효과는 시간적인 결합을 초래하기도 한다. checkPassword함수는 세션을 초기화해도 괜찮을 경우에만 호출이 가능하다.

명령과 조회를 분리하라


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

둘 다 하면 안된다.

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


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

반복하지 마라!


중복을 없애면 모듈 가독성이 크게 높아진다.

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

구조적 프로그래밍


데이크스트라가 제안한 구조적 프로그래밍 원칙인 모든 함수와 함수 내 모든 블록에 입구와 출구가 하나만 존재해야 한다는 함수가 아주 클 때만 상당한 이익을 제공한다.

함수를 작게 만든다면 return, break, continue를 여러 차례 사용해도 괜찮다. 오히려 때로는 단일 입/출구 규칙보다 의도를 표현하기 쉬워진다.

반면, goto문은 큰 함수에서만 의미가 있으므로 작은 함수에서는 피해야만 한다.

함수는 어떻게 짜죠?


소프트웨어를 짜는 행위는 여느 글짓기와 비슷하다.

  1. 처음에는 길고 복잡하다. 들여쓰기 단계도 많도 중복된 루프도 많다. 인수 목록도 아주 길다. 이름은 즉흥적이고 코드는 중복된다.
  2. 하지만 서투른 코드를 빠짐없이 테스트하는 단위 테스트 케이스도 만든다.
  3. 그런 다음 코드를 다듬고, 함수를 만들고, 이름을 바꾸고, 중복을 제거한다.
  4. 메서드를 줄이고 순서를 바꾼다.
  5. 때로는 전체 클래스를 쪼개기도 한다.
  6. 이 와중에도 코드는 항상 단위 테스트를 통과한다.
  7. 최종적으로는 이 장에서 설명한 규칙을 따르는 함수가 얻어진다.

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

실제로 코딩을 해보면 모든 동작들이 함수이고, 다른 사람이 만들어놓은 함수를 살펴봐야 할 일이 정말 많다. 그러다 보면 정말 긴 내용을 가진 함수도 있고, 한 눈에 봤을 때 무슨 동작을 하는 함수인지 예상이 안 되는 함수도 있다. 심지어 내가 짠 함수가 그런 경우도 있었다.

하지만 잘 짜여진 라이브러리나 SDK 등의 함수를 보면 정말 복잡한 동작을 해야 하는 경우에도 겨우 한 두 줄로 짜여진 경우를 자주 볼 수 있었다. 추상화가 굉장히 잘 된 것이다.

이번 장의 내용은 상당히 파격적으로 느껴졌다. 실제로 이번 장에서 소개한 규칙들 중 따르지 않던 규칙이 많이 있었다. 그 중 몇몇은 상황에 따라 따르기 힘든 경우도 있었다.

예를 들어 안드로이드를 개발할 때 context를 굉장히 많이 접하게 된다. 주로 시스템에 어떠한 요청을 할 때 context를 사용하게 되는데 이를 매개 변수로 넘겨야 하는 경우가 흔하다. 이렇게 필수로 넘겨야 하는 매개 변수가 존재하는 경우엔 인수를 0개로 만들기는 힘들어진다. (물론 불필요한 인수를 만들지 말아라는 뜻으로 받아들였다)

처음 코딩을 배울 때 함수는 그저 여러 중복되는 동작을 모아 놓을 수 있는 것 정도로 생각했지만 이제는 함수를 더 잘 만들 방법을 고민해봐야겠다.

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

함수 인수에 대해 설명하는 부분에서 가장 이상적인 인수 개수는 0개라고 주장한다. 일반적인 상황에서 동의하는 내용이다.

하지만 인수를 0개로 만드는 설계를 할 때는 함수의 의존성이 높아질 수 있다고 생각한다. 프로그램의 많은 아키텍처들이 의존성을 낮추고 유지 보수성을 높이기 위해 노력하는데 의존성 관점에서 이 주장을 어떻게 해석해야 할 지 모르겠다.