클린코드 - 03. 함수
어떤 프로그램이든 가장 기본적인 단위가 함수이다.
우리는 어떤 함수를 읽었을때 프로그램 내부를 직관적으로 파악할 수 있을까?
작게 만들어라
- 블록과 들여쓰기
- 중첩 구조가 생길 만큼 함수가 커지면 안된다. (if else문 등 주의하여 쓰자)
- 블록 안에서 호출하는 함수 이름을 적절히 짓는다면 코드를 이해하기 쉽다.
- 한가지만 해라
- 예시: 1. 페이지가 테스트 페이지인지 판단 => 2. 설정 페이지와 해제 페이지를 넣는다 => 3. 페이지를 HTML로 렌더링한다.
- 추상화 수준이 하나인 단계만 수행한다면 그 함수는 한가지 작업을 한다고 할 수 있다.
- 더이상 줄이기가 불가능 하며 if, else를 따로 뺀다고 해도 다른 표현일 뿐 추상화 수준이 바뀌지 않는다.
- 예시: 1. 페이지가 테스트 페이지인지 판단 => 2. 설정 페이지와 해제 페이지를 넣는다 => 3. 페이지를 HTML로 렌더링한다.
- 함수 당 추상화 수준은 하나로!
- 함수가 확실히 '한가지' 작업만 하려면 함수 내 모든 문장의 추상화 수준이 동일해야한다.
- 수준이 섞여있을 경우 근본 개념인지 세부사항인지 구분하기 어려워져 추후에 사람들이 함수에 세부사항을 점점 더 추가하게 된다.
- 위에서 아래로 코드 읽기 (내려가기 규칙)
- 함수 다음에는 추상화 수준이 한 단계 낮은 함수가 온다.
- 즉 위에서 아래로 읽으면 함수 추상화 수준이 한 단계씩 낮아진다.
Switch문
- 다형성을 이용한다.
- 상속관계를 숨긴 후 절대로 다른 코드에 노출하지 않는다.
서술적인 이름을 사용하라
- 길고 서술적인 이름이 짧고 이해하기 어려운 이름보다 좋다. (일관성있게!)
함수 인수
- 이상적인 인수 개수는 0개 (무항)
- 4개 이상은 특별한 이유가 필요하다. (이유가 있어도 사용해서는 안된다..)
- 플래그 인수
- 함수 안에 여러가지 일을 처리하는 것을 의미한다.
- 함수로 부울 값을 넘기는 것은 좋지않다.
- render(boolean isSuite) => renderForSuite(), renderForSingleTest() 로 함수를 나누는 것이 좋다.
- 이항, 삼항 함수
- 인수가 많은 함수는 적은 함수보다 이해하기 어렵다.
- 단항에 비해 위험이 따른다.
- 순서, 무시로 야기되는 문제가 생길 수도 있다.
- 동사와 키워드
- 함수 이름에 인수의 순서, 의도를 넣는것도 좋다.
- assertEqual(expected, actual) => assertExpectedEqualsActual(expected, actual) 이렇게 할 경우 인수의 순서를 기억할 필요가 없다.
- 함수 이름에 인수의 순서, 의도를 넣는것도 좋다.
부수 효과를 일으키지 마라
- checkPass-word일 경우 암호 확인 작업만 하라
- 세션 초기화하는 로직이 있을 경우 문제가 생길 수 있으므로 따로 initializeSession으로 함수를 분리하는 것이 좋다.
명령과 조회를 분리하라
- 수행하거나 답하거나... 분리하라!
오류 코드 보다 예외 케이스를 사용하라
- 명령 함수 에서 오류코드를 반환하는 방식은 명령, 조회 분리 규칙을 미묘하게 위반한다
if (deletePage(page) = E_OK) {
if (registry.deleteReference(page.name) = E_OK) {
if (configKeys.deleteKey(page.name.makeKey()) = E_OK){
logger.log('page deleted');
} else {
logger.log('configKey not deleted');
}
} else {
logger.log('deleteReference from registry failed');
}
} else {
logger.log('delete failed');
return E_ERR0R;
}
// 수정
try {
deletePage(page);
registry.deleteRefe rence(page.name);
configKeys.deleteKey(page.name.makeKey());
}catch (Exception e) {
logger.log(e.getMessage());
}
Try/Catch 블록 뽑아내기
- 정상 동작과 오류 처리 동작을 뒤섞는다. 그러므로 별도의 함수로 뽑아내는 것이 좋다.
public void delete(Page page) {
try {
deletePageAndAllReferences (page);
} catch (Exception e) {
logError(e);
private void deletePageAndAHReferences(Page page)
throws Exception {
deletePage(page);
registry.deleteReference(page.name);
configKeys.deleteKey(page.name.makeKey());
}
private void logError(Exception e) {
logger.log(e.getNlessage());
}
}
- 오류 처리도 한가지 작업이다.
- Error.java 의존성 자석
- enum 열거형 타입을 사용할 경우 의존성이 생겨서 문제가 될 수 있다. (import 해서 사용할 떄 변경이 생기면 매번 재 컴파일 해야하는 문제가 생길 수 있다.)
- 반복하지 마라
- 중복되는 코드를 없앨경우 가독성이 높아진다.
- 객체 지향 프로그래밍은 코드를 부모 클래스로 몰아 중복을 없앤다.
- 구조적 프로그래밍
- 모든 블록에 입구와 출구는 하나만 존재해야한다
- return 문이 하나여야한다. 하지만 함수가 작다면 사용해도 괜찮다.
- goto문은 피해야한다.
- 모든 블록에 입구와 출구는 하나만 존재해야한다
- 함수를 어떻게 짜죠?
- 먼저 생각한대로 기록한 후 읽기 좋게 다듬는다. 초안은 대개 서투르고 어수선하므로 원하는 대로 읽힐때까지 다듬고 정리한다.
내 생각....
역시 책은 내가 사용하는 언어로 된 것을 읽는 것이 가장 베스트인 것같다.
모르는 부분들 혹은 공감하지 못하는 부분들이 존재하는 것을 서서히 느끼고 있다.
하지만 큰 틀은 모두 동일하니 완독하는 것이 목표다.
다른 작업들도 같이 하고 있어 언제 완독할지는 모르겠다.
아 그리고 지금까지 읽은 부분으로 주변 사람들과 가끔 대화를 했는데,
대부분은 맞는 말이지만 아니라고 생각하는 부분들이 존재하기때문에 융통성있게 이점을 배워가면 될 듯하다.
'아티클' 카테고리의 다른 글
Electron 애플리케이션 개발 - 웹 기술로 구현하는 크로스 플랫폼 데스크톱 애플리케이션 (0) | 2021.12.06 |
---|---|
클린코드 - 05~10 (0) | 2021.12.05 |
클린코드 - 04. 주석 (0) | 2021.11.28 |
클린코드 - 02. 의미 있는 이름 (0) | 2021.11.15 |
클린코드 - 01. 깨끗한 코드 (0) | 2021.11.14 |
[아티클 프로젝트 060] 콜 스택(Call stack)과 힙(Heap) (0) | 2020.11.05 |
[아티클 프로젝트 059] 모듈 시스템: CommonJS, AMD, UMD, ES6 (0) | 2020.11.04 |
[아티클 프로젝트 058] 즉시 실행 함수 (IIFE, Immediately-Invoked Function Expression) (0) | 2020.11.03 |