3장 함수
3장 함수
함수를 잘 만드는 방법을 알려주는 챕터.
읽기 쉽고 이해하기 쉬운 함수가 왜 읽기 쉽고 이해하기 쉬운지
의도를 분명히 표현하는 함수를 구현하는 방법
읽는 사람이 프로그램 내부를 직관적으로 파악하게 하는 방법
목차
- 작게 만들어라!
- 블록과 들여쓰기
- 한 가지만 해라!
- 함수 내 섹션
- 함수 당 추상화 수준은 하나로!
- 위에서 아래로 코드 읽기: 내려가기 규칙
- Switch 문
- 서술적인 이름을 사용하라!
- 함수 인수
- 많이 쓰는 단항 형식
- 플래그 인수
- 이항 함수
- 삼항 함수
- 인수 객체
- 인수 목록
- 동사와 키워드
- 부수 효과를 일으키지 마라!
- 출력 인수
- 명령과 조회를 분리하라!
- 오류 코드보다 예외를 사용하라!
- Try/Catch 블록 뽑아내기
- 오류 처리도 한 가지 작업이다
- Error.java 의존성 자석
- 반복하지 마라!
- 구조적 프로그래밍
- 함수를 어떻게 짜죠?
3-1 작게 만들어라!
함수를 만드는 첫 번째 규칙은 ‘작게!’다. 함수를 만드는 두 번째 규칙은 ‘더 작게!’다.
조건문에 들어가는 블록은 한 줄이어야 한다.
3-2 한 가지만 해라!
함수는 한자리를 해야 한다. 그 한 가지를 잘 해야 한다. 그 한가지만을 해야 한다.
저장된 함수 이름 아래에서 추상화 수준이 하나인 단계만 수행해야 한다.
의미 있는 다른 이름으로 다른 함수를 추출할 수 있다면 그 함수는 여러 작업을 하고 있는 것이다.
3-3 함수 당 추상화 수준은 하나로!
추상화 수준을 섞으면 표현이 근본적인 개념인지 세부사항인지
구분하기 어려워 읽는 사람으로 하여금 헷갈리게 한다.
3-3-1 내려가기 규칙
위에서 아래로 이야기처럼 읽혀야 좋은 함수다.
함수 추상화 수준이 한 번에 한 단계씩 낮아진다.
3-4 Switch 문
기다란 switch문의 반복은 추상 팩토리 & 다형성 객체 생성 코드로 개선할 수 있다.
3-5 서술적인 이름을 사용하라
코드를 읽으면서 짐작했던 기능을 각 루틴이 그대로 수행한다면 깨끗한 코드라 불러도 되겠다.
함수가 작고 단순해야 하고, 하는 일을 이름에 잘 표현해야 한다.
3-6 함수 인수
이상적인 인수 개수는 0개( 무항 )이다. 다음은 1개( 단항 )이고, 다음은 2개( 이항 )다.
인수는 개념을 이해하기 어렵게 만든다.
별로 중요하지 않은 세부사항임에도 불구하고, 발견할 때마다 의미를 해석해야 하기 때문이다.
인수가 생기면 모든 경우의 수를 검증하는 테스트 케이스를 작성하기 복잡해진다.
3-6-1 많이 쓰는 단항 형식
이름과 문맥을 주의해 단항 형식을 사용한다.
void transform(StringBuffer pageText)
위와 같은 변환 함수에서 출력 인수를 사용하면 혼란을 일으킨다.
입력 인수를 변환하는 함수라면 반환 결과는 반환값으로 돌려준다.
StringBuffer transform(StringBuffer pageText)
입력 인수를 그대로 돌려주는 함수라 할지라도 변환 함수 형식을 따르는 편이 좋다.
3-6-2 플래그 함수
플래그 함수는 추하다.
함수로 진리 값을 넘기는 관례는 정말 끔찍하다.
함수로 진리 값을 넘긴다는 것은 함수가 한꺼번에 여러 가지를 처리한다고 대놓고 공표하는 셈이다
플래그는 참이면 참에 대한 로직, 거짓이라면 거짓에 대한 로직 즉 하나의 함수가 이것 저것한다.
3-6-3 이항 함수
인수가 2개인 함수는 단항 함수보다 이해하기 어렵다.
이항 함수가 무조건 나쁘다는 말은 아니다.
하지만 가능하면 단항 함수로 바꾸도록 애써야 한다.
3-6-4 삼항 함수
인수가 3개인 함수는 이항 함수보다 문제가 두 배 이상 늘어난다.
따라서 삼항 함수를 만들 때는 신중히 고려해야 한다.
3-6-5 인수 객체
인수가 2개, 3개 필요하다면 일부를 클래스 변수로 선언하는 방법을 가져본다.
Circle makeCircle(double x, double y, double radius)
Circle makeCircle(Point center, double radius)
이는 객체를 이용한 눈속임이 아니다.
개념을 표현하는 방법이다.
3-6-6 인수 목록
때로는 인수 개수가 가변적인 함수도 필요하다.
하지만 가변 인수를 취하는 함수는 단항, 이항, 삼항 함수로 취급될 수 있는 사실을 명시하자.
3-6-7 동사와 키워드
단항 함수는 함수와 인수가 동사, 명사 쌍을 이루어야 한다.
write(name)
함수 이름에 인수에 관한 키워드를 추가해라.
write(name)
writeField(name)
assertEquals()
assertExpectedEqualsActual(expected, actual)
3-7 부수 효과를 일으키지 마라
예상치 못한 부수 효과는 시간적인 결합, 순서 종속성을 초래하게 된다.
함수는 한 가지 기능만 하도록 작성하라.
3-8 명령과 조회를 분리하라
함수는 무언가를 수행하거나, 무언가에 답하거나 두 가지 중 하나만 기능해야 한다.
나쁜 예시
if(setName("userName", "juwon"))
좋은 예시
if(nameExists("userName")){
setName("userName", "juwon")
}
3-9 오류 코드보다 예외를 사용하라
오류 코드를 반환하는 방식은 여러 단계로 중첩되는 코드를 발생시킨다.
오류 코드를 반환하는 방식은 오류 코드를 곧바로 처리해야 한다는 문제가 발생한다.
오류 코드를 정의하는 의존성 자석( magnet )은 재컴파일, 재배치를 요구하기 때문에 번거로워진다.
3-9-1 Try/Catch 블록
Try/Catch 블록을 별도의 함수로 뽑아내고, try문 안에서 실제 작업할 메소드를 호출한다.
실제 작업을 하는 코드에서는 throws Exception하여 모든 예외 처리를 한 곳에서 처리한다.
3-10 반복하지 마라
어쩌면 중복은 소프트웨어에서 모든 악의 근원이다
코드의 길이가 늘어난다.
알고리즘이 변하면 중복된 코드를 모두 수정해야 한다.
오류가 발생할 확률도 몇 배로 높아진다.
3-11 구조적 프로그래밍
모든 함수와 함수 내 모든 블록에 입구와 출구가 하나만 존재해야 한다.
함수가 아주 클 때 구조적 프로그래밍의 목표와 규율이 효과적이다.
3-12 함수를 어떻게 짜죠?
처음부터 이번 장에서 소개한 방법으로 코드를 짜는 사람은 없다.
가능한 사람도 없다.
처음에는 이름은 즉흥적이고 코드는 중복된다.
하지만 이런 코드를 빠짐없이 테스트하는 단위 테스트 케이스를 만든다.
그 다음 코드를 수정하고 함수를 만들고 이름을 바꾸고 중복을 제거한다.
결과적으로 메소드를 줄이고 순서를 바꾼다.
때로는 전체 클래스를 쪼개기도 한다.
결론
함수는 동사이며 클래스는 명사다.
프로그래밍의 기술은 언제나 언어 설계의 기술이다.
프로그래밍 언어라는 수단을 사용해 풍부하고 표현력이 강한 언어로 만들어 간다.
시스템에서 발생하는 동작을 함수로 설명하는 것이며 재귀라는 기교로 해당 도메인에 특화된 자신만의 이야기를 풀어나간다.
이 3장에서는 함수를 잘 만드는 기교를 소개했다.
위에서 설명한 규칙을 따른다면 길이가 짧고 이름이 좋고 체계가 잡힌 함수가 나오리라.
하지만 프로그래머의 진짜 목적은 시스템이라는 이야기를 풀어가는데 있는 사실을 명심해야한다.
4장 주석
'Etc > Clean Code[ Robert C. Martin ]' 카테고리의 다른 글
[Clean Code] 6장 객체와 자료구조 (0) | 2022.04.10 |
---|---|
[Clean Code] 5장 형식 맞추기 (0) | 2022.04.07 |
[Clean Code] 4장 주석 (0) | 2022.04.04 |
[Clean Code] 2장 의미있는 이름 (0) | 2022.04.02 |
[Clean Code] 1장 깨끗한 코드란?? (0) | 2022.04.02 |