Clean Code - 로버트 C. 마틴
3장, 함수
함수를 처음 읽는 사람이 프로그램 내부를 직관적으로 파악 할 수 있어야 함
1. 작게 만들기
- 얼마나 작게 만들어야 할까? ➡ 모든 함수를 4줄 이내로
🚧 if / else/ while 문 등에 들어가는 블록은 한 줄이어야 함
Clean Code
public static String renderPageWithSetupsAndTeardowns(PageData pageData, boolean isSuite) throws Exception{
if(isTestPage(pageData)){
includeSetupAndTeardownPages(pageData, isSuite);
}
return pageData.getHtml();
}
➡ if문 안에는 하나의 함수로 감싸져 있음
➡ 바깥 함수가 작아짐
- 각 함수가 할 이야기는 명백하게 하나의 이야기만 표현
2. 한 가지 처리만
- 한 가지가 무엇인지 알기 어려움
➡ 추상화 수준에서 여러 단계로 나눠서 수행이 가능한가?
➡ 의미가 있는 다른 함수로 추출할 수 있는가?
3. 함수 당 추상화 수준은 하나
- 함수가 한 가지 작업만 하기 위해서는 모든 문장의 추상화 수준이 동일해야 함
➡ 근본 개념과 세부 개념이 뒤섞일 수 있음
- 코드에 일관성이 생김
👀 내려가기 규칙
코드가 위에서 아래로 이야기처럼 읽힐 때, 한 함수 다음에 추상화 수준이 한 단계 낮은 함수가 오는 것
if(조건1){ if(조건2){ } }
➡ 조건1의 내용은 조건2의 내용이 포함되어 있다.
➡ 조건2는 조건1보다 구체적인 추상화 내용을 담고 있다.
4. Switch 문
- 다형성(polymorphism)을 이용하면 swtich 문을 반복하지 않을 수 있음
ex)
Bad Code
public Money calculatePay(Employee e) throws InvalidEmployeeType{
switch (e.type){
case COMMISSIONED:
return calculateCommistionedPay(e);
case HOURLY:
return calculateHourlyPay(e);
case SALARIED:
return calculateHourlyPay(e);
default:
throw new InvalidEmployeeType(e.type);
}
}
- 함수의 길이가 김
- 한 가지 작업만 수행하지 않음
- SRP(Single Responsibility Principle)을 위반함
SRP(Single Responsibility Principle): 단일 책임 원칙
- 모든 클래스는 하나의 책임만을 가지며, 클래스는 그 책임을 완전히 캡슐화 해야 함
- OCP(Open Close Principle) 위반
OCP(Open Close Principle): 개방-폐쇄 원칙
- 소프트웨어 개체는 확장에 대해 열려있어야 하고, 수정에 대해서 닫혀있어야 함
- ⭐ 동일한 구조의 함수가 무한정 존재 할 수 있음
ex) isPayday(Employee e, Date date);
Clean Code
- 추상화 레벨로 상속 관계를 숨김
- 단 한번만 switch문 사용 ➡ 다형성 객체 생성 코드에서만 사용
5. 서술적인 이름 사용
- 코드를 읽으면서 짐작했던 기능을 각 루틴 그대로 수행하면 깨끗한 코드
6. 함수 인수
- 인수가 적을수록 좋은 코드, 테스트도 쉬움
- 출력 인수는 입력 인수보다 더 이해하기 어려움
- 플래그 인수(boolean)는 사용하지 않는 것이 좋음
인수 객체
// 1번
Circle makeCircle(double x, double y, double radius);
// 2번
Circle makeCircle(Point center, double radius);
- 2-3개의 인수 일부를 독자적인 클래스 변수로 선언
➡ 변수를 묶어서 넘기기 위해서는 이름을 붙여야 하므로 개념을 표현하게 됨
인수 목록
void dyad(String name, Integer... args); //인수가 두개
- 인수 목록은 하나의 항으로 취급
7. 부수 효과❌
- 예상하지 못하게 클래스를 수정하면서 함수에서 여러가지 기능을 수행
▶️ 시간적 결합(temporal coupling), 순서 종속성(order dependency) 초래
- 함수 이름에 분명하게 기능을 명시
- 출력인수를 거의 사용하지 않음
//Bad Code
appendFooter(s); //s의 의미는?
//함수 선언부를 찾아서 s가 무슨 의미인지를 파악해야 함
-->public void appendFooter(StringBuffer report)
//Clean Code
report.appendFooter(); //this를 이용하여 함수 실행
8. 명령과 조회 분리
- 함수는 1️⃣ 수행하거나 2️⃣ 답하거나 둘 중 하나만 해야함
ex) 객체 상태 변경 or 객체 정보 반환
Bad Code
public boolean set(String attribute, String value);
//--------//
if (set ("username", "unclebob"))
- 함수 호출로 봐서 코드가 모호
- set 함수가 username을 unclebob로 되어있는지 확인하는 코드인지, 셋팅을 하는 코드인지 알 수 없음
Clean Code
- 명령과 조회를 분리
if (attributeExists("username")){
setAttribute("username", "unclebob");
}
9. 오류 코드보다 예외 사용
- try/catch는 별도 함수로 사용
- 정상 동작과 오류처리 동작 분리
public void delete(Page page){
try{
deletePageAndAllReferences(page); //실제 페이지를 제거하는 함수
}
catch (Exception e){
logError(e);
}
}
> 모든 오류 처리는 delete
> 실제 행동은 deletePageAndAllReferences가 실행
- 오류도 한 가지 동작만 사용
Bad Code
- 오류 코드 사용 시, 오류를 바로 처리해야 함
- 중첩되는 문제 발생
Clean Code
- 코드가 간편해짐
Erro.java
public enum Error{
OK,
INVALID,
NO_SUCH,
LOCKED,
OUT_OF_RESOURCES,
WAITING_FOR_EVENT;
}
- 오류 코드 정의
- 오류코드 대신 예외를 사용하면 재컴파일/재배치 없이 새 예외 클래스 추가 가능
10. 중복 금지
- 부모 클래스를 이용하여 중복을 없앰
- 구조적 프로그래밍, AOP, COP 등 중복 제거 전략
구조적 프로그래밍
* 함수가 클 때만 이익을 제공하므로 작을 때는 아래 규칙을 지키지 않아도 됨
- 모든 함수와 함수 내 모든 블록에 입구와 출구가 하나만 존재해야 함 (return문 하나)
- 루프 안에 break, continue 사용❌
- goto는 절대 사용❌
'IT > 책' 카테고리의 다른 글
[Clean Code] 7장, 오류 처리 (0) | 2021.11.07 |
---|---|
[Clean Code] 6장, 객체와 자료 구조 (0) | 2021.11.05 |
[Clean Code] 5장, 형식 맞추기 (0) | 2021.10.30 |
[Clean Code] 4장, 주석 (0) | 2021.10.30 |
[Clean Code] 2장, 의미 있는 이름 (0) | 2021.10.25 |