#작게_만들어라
- 80년대에는 한 함수가 한 화면을 넘어가면 안된다고 했다
- 당시 VT100 화면은 가로 80 세로 24줄이었는데 편집기가 4줄을 관리용으로 사용했기 때문
- 얼마나 짧아야하는가?
- 20줄도 길다
- if/else/while 블록은 한줄 -> 대게 여기서 함수 호출
- 즉 중첩이 생길만큼 함수가 커선 안된다는 의미 (들여쓰기는 1,2에서 그치도록)
"함수는 한 가지를 해야 한다. 그 한 가지를 잘 해야 한다. 그 한 가지만을 해야 한다"
#한가지만_해라
- 한가지의 기준은?
- 추상화 수준 : 지정된 함수 이름 아래 추상화 수준이 하나인 단계만 수행하면 작업 갯수는 하나인 것
- 의미 있는 이름으로 다른 함수를 추출할 수 있다면 여러 작업
- 여러 섹션으로 나눈다는건 여러 작업을 한다는 증거
#코드는_위에서_아래로_이야기처럼
- 추상화 수준이 한 단계씩 낮아지는 모양
#Switch문
- 본질적로 if/else를 포함한 swiitch문은 N가지 작업을 처리하므로 작게 만들기 어려움
- 각 분기문을 저차원 클래스에 숨기고 반복하지 않는 방법 존재
- 다형성을 이용
- 상속 관계로 숨겨 다른 코드에 노출하지 않는다
#서술적인_이름_사용
- 코드를 읽으면서 짐작했던 기능을 각 루틴이 그대로 수행한다면 깨끗한 코드!
- 작은 함수에 좋은 이름이 붙는다면 절반은 성공하겠지
- 길어지는것에 겁먹지 말것. 주석으로 쓰느니 이름으로 써라.
- 명명법
- 여러 단어가 쉽게 읽히게
- 여러 단어를 사용해 함수 기능을 잘 표현하게
- 모듈 내 함수 이름의 문구, 명사, 동사 통일
- ex) includeSetupAndTeardownPages, includeSetupPages ... (접미사처럼)
#함수_인수는_적을수록_좋다
- 무항, 다음이 단항, 다음은 이항 순으로 이상적 -> 3개 이상은 피하는게 좋다 (복-잡)
#이상적인_단항_함수
- 인수에 질문을 던지는 경우
- ex) boolean fileExists("MyFile") : 있니 없니~
- 인수를 변환해 결과를 반환하는 경우
- ex) InputStream fileOpen("MyFile") : string을 InputStream으로
- 변환 함수라면 결과를 반환 값으로 돌려줘야 (그대로 돌려주더라도 반환 형태를 명시할 것)
- 이벤트 함수
- 입력 인수로 시스템 상태 변경 (입력만 있고 출력이 없는 형태)
- 명확히 드러내서 조심히 사용
#비추천_함수
- 플래그 인수 (terrible)
- bool을 인수로 넘기는건 정말 끔찍. 함수가 여러 가지를 처리한다고 대놓고 공표하는 셈
- 이항 함수 (soso)
- 단항보다 이해하기 어렵다
- 꼭 필요한 경우도 있지만 위험이 수반된다는 걸 기억하고 단항으로 바꾸도록 노력할 것
- 삼항 함수 (bad)
- 이항보다 이해하기 어렵다
#인수_객체
- 이항, 삼항 이상의 인수가 필요하다면 일부를 독자적 클래스 변수로 선언
- 두개 묶어서 포인터로 넘기는 식
#인수_목록
- 인수 개수가 가변적인 경우 List 활용
- 논리적으론 단항/이항/삼항 규칙에 벗어나지 않음. 이상 넘지 않도록 유의
#동사와_키워드
- 단항 함수 네이밍 : 동사/명사의 쌍
- 함수 이름에 키워드 추가 : 함수 이름에 인수 이름 포함
#남몰래_부수_효과_금지
- 한가지 동작 한대놓고 다른 짓하면 시간적인 결합이나 순서 종속성을 초래
- 시간적인 결합(Temporal Coupling) : 특정 상황에서만 호출 가능하게 됨
- 순서 종속성(Order Depandency) : 정해진 순서에 의해서만 호출 가능하게 됨
#시키거나_하거나_둘중_하나만
- 명령과 조회 분리 : 객체 상태를 변경or 객체 정보를 반환 (쉽게 말해 get/set 따로 두라는 말)
#오류코드_말고_예외처리
- 명령 함수에서 오류 코드 반환하면 분리 규칙을 미묘하게 위반하게 됨
- if (deletePage(page) == E_OK) 같이 명령을 표현식으로 많이 사용하게 되기 때문
- 오류 코드로 인해 분기처리 하지 말고 예외로써 try/catch를 활용해준다
#Try/Catch_별도_함수로
- 원래 try/catch가 코드 구조에 혼란을 일으키며 정상 동작과 오류 처리를 뒤섞는 나쁜 구조이므로 try/catch 블록은 별도 함수로 뽑아낸다
- 즉 정상 동작과 오류 처리 동작을 따로 함수로 뽑는다
- 물론 오류처리도 한번에 한 가지 작업만 해야함
- try로 시작하면 catch, finally로 끝나야 하지 다른거 섞이면 ㄴㄴ
#오류_코드_정의
- 오류 코드를 반환하게 된다면 어디선가 오류 코드를 enum 처럼 정의하고 있을 것
- 이런 클래스를 의존성 자석(magnet)이라 함
- 이거 고치면 얘 사용하는 클래스 모두 재컴파일
- 따라서 새 오류 코드를 추가하는게 아닌 기존 오류 코드를 재사용하는 방식 선호
- 물론 오류 코드 대신 예외 사용하면 편함
#반복_금지
- 중복은 소프트웨어에서 모든 악의 근원
- 많은 원칙과 기법이 중복을 없애거나 제어할 목적으로 나오게된 것
- ex) 자료에서 중복을 제거할 목적으로 관계형 데이터베이스에 정규 형식을 만듦
- ex) OOP에서는 코드를 부모 클래스로 몰아 중복을 없앰
- ex) 그 외 AOP(Aspect Oritented Programming), COP(Component Oriented Programming) 등
#구조적_프로그래밍
- 모든 함수와 함수 내 모든 블록에 입구와 출구가 하나만 존재하는 것
- 즉 함수는 return 문이 하나여야함
- loop내 break/continue 사용 지양
- goto는 절대절대 금지
- 물론 함수를 애초에 작게 설계했으면 문제되지 않음
- 오히려 break,continue,return 여러번 해도 의도 표현이 명확해짐
- 함수가 클 땐 저 원칙을 지키면 꽤나 이득일지도?
- 그치만 작은 함수에서도 goto는 피해라
#개발은_글짓기다
- 초안에서 고치고 정리하다보면 좋아지는 것
- 코드를 빠짐없이 테스트할 수 있는 단위 테스트 케이스도 잘 만들어야함
#끝으로
- 모든 시스템은 DSL(Domain Specific Language, 도메인 특화 언어)로 만들어짐
- 특정 응용 분야 시스템을 기술할 목적
- 함수는 그 언어에서 동사, 클래스는 명사
- 프로그래밍은 언어 설계의 기술
- 즉 시스템은 (구현할) 프로그램이 아닌 (풀어갈) 이야기
- 언어라는 수단을 사용해 좀 더 풍부하고 좀 더 표현력이 강한 언어를 만들어 이야기를 풀어가는 것
- 앞선 규칙을 잘 따르면 짧고, 좋은 이름의 체계가 잡힌 함수가 나오겠지만
- 단지 함수가 분명하고 정확한 언어로 깔끔하게 맞아 떨어져야 이야기를 풀어가기 쉬워지는 것
- 진짜 목표는 시스템이라는 이야기를 풀어가는 데 있다
'Book > Clean Code' 카테고리의 다른 글
제 2장 의미 있는 이름 (0) | 2021.04.11 |
---|---|
제 1장 깨끗한 코드 (0) | 2021.04.03 |
댓글