함수를 작성한다는 것은 글을 작성하는 것과 닮아 있다.
함수는 한 가지를 해야 한다. 그 한 가지를 잘 해야 한다. 그 한가지만을 해야 한다.
추상화 수준이 하나인 단계만 수행한다면 그 함수는 한 가지 작업만 한다. 우리가 함수를 만드는 이유는 큰 개념을 다음 추상화 수준에서 여러 단계로 나뉘 수행하기 위해서이다.
한 함수 내에 추상화 수준이 섞이면 읽는 사람이 헷갈린다. 특정 표현이 근본 개념인지 아니면 세부사항인지 구분하기 어려울 뿐만 아니라, 깨어진 창문처럼 사람들이 함수에 세부사항을 점점 추가한다.
//TODO Target
- 만약 함수의 인수가 1개라면?
인수에 질문을 던지는 경우. boolean fileExists("MyFile" )
이 좋은 예. 또는 인수를 뭔가로 변환해 결과를 반환하는 경우.
- 만약 함수의 인수가 2개라면?
인수가 2개는 1개보다 더 복잡하다.
2개 인수의 함수를 사용하는 것은 그 만큼 위험이 따른다는 사실을 인지하고, 가능하다면 단한 함수로 변경되도록 노력해야 한다.
- 만약 함수의 인수가 3개라면?
신중히 고려해서 만들자. 인수가 3개는 2개 보다도 더욱 이해하기 어렵다.
- 만약 함수의 인수가 가변인자라면?
대표적인 좋은 예시가 String.format("%s", hours)
오류 코드를 사용한다는 것은 명령/조회 분리 규칙을 미묘하게 위반한다. "만약 이런 에러 코드일 경우에는 이렇게 하라!" 라는 식의 행태가 될 것이다.
Try/Catch 블록 뽑아내기
코드 구조에 혼란을 일으키며, 정상 동작과 오류 처리 동작이 뒤섞여있다. 그러므로 try/catch 블록을 별도 함수로 뽑아내라.
시스템을 (구현할) 프로그램이 아니라 (풀어갈) 이야기로 여기자. 프로그래밍 언어라는 수단을 사용해 좀 더 풍부하고 좀 더 표현력이 강한 언어를 만들어 이야기를 풀어나가자. 시스템에서 발생하는 모든 동작을 설명하는 함수 계층이 바로 그 언어에 속한다.
길이가 짫고, 이름이 좋고, 체계가 잡힌 함수가 나와서 시스템이라는 이야기를 풀어가는 데 있다는 사실을 명심하자.
처음 접하는 코드를 보면 나도 모르게, 깨진 유리창처럼 함수에 점점 더 많은 세부사항을 추가하려고 한다. 가장 인상 깊었던 부분은 한 함수는 추상화 수준이 하나인 단계만 수행한다면 그 함수는 한 가지 작업만 한다. 라는 것이다.
개념을 드러내는 함수를 작성하는 것과 함수 안에 세부사항을 추가하는 것은 다르다.
추상화가 한 개였던 클래스가 있었다. 그리고 문제를 쉽게 해결하기 위해 추상화 수준을 낮추게 되는데, 이는 깨진 유리창와 유사하다.
public interface NotificationTarget<T> {
EnvelopeNotificationId getId();
NotificationType getType();
Notification getNotification();
Factor getPayload();
default Notification getPayload2() {
return getNotification();
}
}
NotificationTarget 는 태초에 하나의 GetType() 만 가졌었다. 그러나, NotificationTarget 에 의존하는 객체들이 들어감에 따라 새로운 데이터가 필요함을 느끼고, 데이터적인 관점에서 타 메소드가 추가되었다.