본문 바로가기
RECORDS/CleanCode

클린코드 #3

by _wavy 2024. 3. 4.

3장 함수

클린한 함수 구현법을 소개하는 장. 함수란 프로그램의 기본 단위이므로 가독성 있는 함수란 읽는 사람이 프로그램 내부를 직관적으로 파악할 수 있는 코드를 말한다. 그를 위한 함수는 크기가 작고 한가지 일만 수행해야 한다.(아래의 순서는 내가 이해하기 쉽도록 임의로 섞어서 그룹핑 해 둔 것이다.)

 

1. 작게

  • 작게 만들어라: 내부의 들여쓰기 레벨을 2단계 이하로

2. 한가지만

  • 한가지만 해라
    • "함수에서 의미있는 이름으로 다른 함수를 추출할 수 있다면 그 함수는 여러 작업을 하는 셈이다."
  • 함수당 추상화 수준은 하나로: 근본개념과 세부사항을 구분
  • switch 문: 사용 지양, N가지를 처리하므로
  • 부수 효과를 일으키지 마라: 시간, 순서적 종속성이 발생함. 피치못한 경우 checkPWAndInitSession처럼 함수명에 표시, 이 경우 한가지만 수행한다는 규칙을 어기게 됨
  • 명령과 조회를 분리하라
  • 오류 코드보다 예외를 사용하라: try-catch-finally 블록을 함수로 분리
// 오류 코드보다 예외를 사용하라: 오류 코드는 명령/조회가 같이 이루어지므로

function delete(page: Page): void { // 예외 처리 함수
  try {
    deletePageAndAllReferences(page);
  } catch (e) {
    logError(e);
  }
}

function deletePageAndAllReferences(page: Page): void { // 실제 동작 함수
  deletePage(page);
  registry.deleteReference(page.name);
  configKeys.deleteKey(page.name.makeKey());
}

function logError(e: Error): void { // 에러 처리 함수
  logger.log(e.getMessage());
}

 

3. 직관적으로

  • "코드는 위에서 아래로 읽어내려가면서 이야기처럼 읽히도록 작성한다."
  • 서술적인 이름을 사용하라
    • 함수-인수가 동사-명사쌍을 이루게 하라 
    • ex) includeSetupAndTeardownPages()isTestable(data)write(name)
  • 함수 인수: 인수는 적을수록 좋다. 개념 이해를 어렵게 하고, 테스트 케이스 작성이 힘들어지므로
    • 단항 함수: 불린 함수 / 반환 함수 / 이벤트 함수
    • 이항 이상 함수: 인수에 자연스러운 순서가 있는 경우 / 그렇지 않으면 함수명에 순서 표기
/* ☝ 인수 1개(단항 함수) */
// 1) 불린 함수: 인수에 질문 던지기
fileExists(myfile) // ↪ true || false

// 2) 반환 함수: 인수를 변환해 결과로 반환
fileOpen(myfile) // ↪ inputStream

// 3) 이벤트
eventHandler(event) // ↪ void

/* BAD: 위 세 경우를 제외한 단항 함수 케이스 */
// ex. 변형 함수
function manipulatePageData(pageData: string): void {
	// 입력값인 pageData를 변형
}

// ex. 플래그 함수: 불리언 인수는 추하다.
render(isSuite) ➜ renderForSingleTest() + renderForSuite()

/* ✌ 인수 2개(이항 함수) */ 
// 인수 항에 자연스러운 순서가 있는 경우 사용: 좌표
const point = new Point(x, y)

// 인수 순서를 함수명에 표시
assertEquals(expected, actual) ➜ assertExpectedEqualsActual(expected, actual)
  • 반복하지 마라
  • 구조적 프로그래밍

TIL

함수형 프로그래밍에 대한 지식 없이 구현 코드를 짜오면서 기능은 돌아가나 정리가 안 된 코드를 반복해왔다. 이 때문에 고민하던 내겐 가장 와닿았던 챕터.

 

최근 짰던 node 모듈에서도 분기 케이스를 switch 문으로 처리했었는데 처음 구상했던 코드에서 case가 늘어나고 로직이 복잡해지면서 함수가 비대해지는 것을 경험했었다. 직접 구현한 내게도 코드 수정이 번거로웠는데 다른 사람에게 읽어보라고 하면... 이런 경우 아무리 힘들게 짠 코드라도 다시 돌아보기 싫은 것이 된다.😤

 

챕터를 돌려 읽어보면서 그 못생긴 코드를 대입해보게 되었다. 그리고 전체 코드가 길어지더라도 더 서술적인 함수명과 함께 작고 단일한 역할의 함수들로 쪼개어 구현하는 것이 더 좋은 방법인 것 같다고 납득했다. 앞으로의 함수 구현을 어떻게 하는 게 좋을까- 여기에 대한 힌트가 책에 한문장으로 나와있다.

 

각 함수는 다음 함수를 소개하며 각 함수는 일정한 추상화 수준을 유지

 

들여쓰기를 지양하고 최대한 미니멀한 함수를 구현하며 글쓰기처럼 생각하는 것이 요령인 것 같다. 이렇게 작성하려면 코드 구상 단계에서부터 프로세스가 달라져야 하지 않을까 싶다. 그리고 정말 글쓰기를 하듯이 코드 퇴고 과정을 거치면서 불필요한 depth, 인수, 중복을 제거하는 과정을 추가로 거쳐야 할 것 같다. 좋은 코드를 쓰는 것은 당연하지만 쉽지 않은 것이다...

'RECORDS > CleanCode' 카테고리의 다른 글

클린코드 #4  (0) 2024.03.06
클린코드 #1-2  (0) 2024.03.04
클린코드 #0  (0) 2024.03.01

댓글