📌 함수
작게 만들어라!
- 함수를 만드는 규칙은 '작게!'다! 함수를 만드는 둘째 규칙은 '더 작게!'다.
- if 문/else 문/while 문 등에 들어가는 블록은 한 줄이어야 한다는 의미다.
- 중첩 구조가 생길 만큼 함수가 커져서는 안 된다는 뜻이다.
- 함수에서 들여쓰기 수준은 1단이나 2단을 넘어서면 안 된다.
한 가지만 해라!
- 함수는 한 가지를 해야 한다. 그 한 가지를 잘 해야 한다. 그 한 가지만을 해야 한다.
- 지정된 함수 이름 아래에서 추상화 수준이 하나인 단계만 수행한다면 그 함수는 한 가지 작업만 한다.
- 단순히 다른 표현이 아니라 의미 있는 이름으로 다른 함수를 추출할 수 있다면 그 함수는 여러 작업을 하는 셈이다.
함수당 추상화 수준은 하나로!
- 함수 내 모든 문장의 추상화 수준이 동일해야 한다.
위에서 아래로 코드 읽기: 내려가기 규칙
- 위에서 아래로 프로그램을 읽으면 함수 추상화 수준이 한 번에 한 단계씩 낮아진다.
Switch 문
- 본질적으로 switch 문은 N 가지를 처리한다. 각 switch 문을 저차원 클래스에 숨기고 절대로 반복하지 않는 방법은 있다. 물론 다형성을 이용한다.
서술적인 이름을 사용하라!
- 함수가 작고 단순할수록 서술적인 이름을 고르기도 쉬워진다.
- 함수 이름을 정할 때는 여러 단어가 쉽게 읽히는 명명법을 사용한다.
- 그다음, 여러 단어를 사용해 함수 기능을 잘 표현하는 이름을 선택한다.
- 이름을 붙일 때는 일관성이 있어야 한다.
- 모듈 내에서 함수 이름은 같은 문구, 명사, 동사를 사용한다.
함수 인수
- 함수에서 이상적인 인수 개수는 0개(무항)다. 다음은 1개(단항)고, 다음은 2개(이항)다.
많이 쓰는 단항 형식
- 함수에 인수 1개를 넘기는 이유로 가장 흔한 경우는 두 가지다. 하나는 인수에 질문을 던지는 경우다. 다른 하나는 인수를 뭔가로 변환해 결과를 반환하는 경우다.
- 아주 유용한 단항 함수 형식이 이벤트다.
이항 함수
- 인수가 2개인 함수는 인수가 1개인 함수보다 이해하기 어렵다.
- 이항 함수가 무조건 나쁘다는 소리는 아니다. 하지만 그만큼 위험이 따른다는 사실을 이해하고 가능하면 단항 함수로 바꾸도록 애써야 한다.
삼항 함수
- 삼항 함수를 만들 때는 신중히 고려하라 권고한다.
인수 객체
- 인수가 2-3개 필요하다면 일부를 독자적인 클래스 변수로 선언할 가능성을 짚어본다.
동사와 키워드
- 단항 함수는 함수와 인수가 동사/명사 쌍을 이뤄야 한다.
- write(name) → writeField(name)
부수 효과를 일으키지 마라!
- 부수 효과는 거짓말이다. 함수에서 한 가지를 하겠다고 약속하고선 남몰래 다른 짓도 하니까.
출력 인수
- 일반적으로 우리는 인수를 함수 입력으로 해석한다.
- 객체 지향 언어에서는 출력 인수를 사용할 필요가 거의 없다. 출력 인수로 사용하라고 설계한 변수가 바로 this이기 때문이다.
명령과 조회를 분리하라!
- 함수는 뭔가를 수행하거나 뭔가에 답하거나 둘 중 하나만 해야 한다.
- 객체 상태를 변경하거나 아니면 객체 정보를 반환하거나 둘 중 하나다.
오류 코드보다 예외를 사용하라!
- 명령 함수에서 오류 코드를 반환하는 방식은 명령/조회 분리 규칙을 미묘하게 위반한다.
- 오류 코드 대신 예외를 사용하면 오류 처리 코드가 원래 코드에서 분리되므로 코드가 깔끔해진다.
Try/Catch 블록 뽑아내기
- try/catch 블록을 별도 함수로 뽑아내는 편이 좋다.
- 정상 동작과 오류 처리 동작을 분리하면 코드를 이해하고 수정하기 쉬워진다.
오류 처리도 한 가지 작업이다.
- 오류를 처리하는 함수는 오류만 처리해야 마땅하다.
- 함수에 키워드 try가 있다면 함수는 try 문으로 시작해 catch/finally 문으로 끝나야 한다는 말이다.
반복하지 마라!
- 많은 원칙과 기법이 중복을 없애거나 제어할 목적으로 나왔다.
- 객체 지향 프로그래밍은 코드를 부모 클래스로 몰아 중복을 없앤다.
구조적 프로그래밍
- 함수는 return 문이 하나여야 한다.
- 함수를 작게 만든다면 간혹 return, break, continue를 여러 차례 사용해도 괜찮다.
함수를 어떻게 짜죠?
- 소프트웨어를 짜는 행위는 여느 글짓기와 비슷하다. 먼저 생각을 기록한 후 읽기 좋게 다듬는다.
- 처음에는 길고 복잡하다. 들여쓰기 단계도 많고 중복된 루프도 많다. 인수 목록도 아주 길다. 이름은 즉흥적이고 코드는 중복된다. 하지만 그 서투른 코드를 빠짐없이 테스트하는 단위 테스트 케이스도 만든다.
- 그런 다음 코드를 다듬고, 함수를 만들고, 이름을 바꾸고, 중복을 제거한다. 메서드를 줄이고 순서를 바꾼다. 때로는 전체 클래스를 쪼개기도 한다.
- 처음부터 탁 짜내지 않는다. 그게 가능한 사람은 없으리라.
결론
- 함수는 언어에서 동사며, 클래스는 명사다.
- 대가(master) 프로그래머는 시스템을 (구현할) 프로그램이 아니라 (풀어갈) 이야기로 여긴다.
- 프로그래밍 언어라는 수단을 사용해 좀 더 풍부하고 좀 더 표현력이 강한 언어를 만들어 이야기를 풀어간다.
- 여러분이 작성하는 함수가 분명하고 정확한 언어로 깔끔하게 같이 맞아떨어져야 이야기를 풀어가기가 쉬워진다는 사실을 기억하기 바란다.
📘 나는 그동안 함수 만들기의 가장 기본인 '한 가지만 하는가'를 잘 지켰는지 돌아보게 되었다. 이번 3장에서 가장 와닿았던 부분은 '시스템을 구현하는 것이 아니라 풀어가야 하는 것'이다. 무언가를 풀려고 하기보다는 빨리 완성시키기 위해 기능이 구현되면 바로 다음 작업으로 넘어가는 일이 다반사였다. 글짓기처럼 함수를 만들 때도 여러 번의 수정 작업이 필요하다는 것을 알게 되었다. 깔끔하고 좋은 함수를 짜기 위해 여러 번의 수정과 개선을 거치는 과정이 필수적임을 깨달았다. 단순히 기능을 구현하는 것에 그치지 않고, 더 나은 구조와 가독성을 위해 함수를 지속적으로 다듬어야 한다. 기한이 있는 프로젝트에서는 이 부분을 어떻게 적용시킬 수 있을지 고민해 봐야겠다.