노트

단계 쪼개기

Split Phase

설계#refactoring · 연결된 개념 5개

쉽게 말하면

단계 쪼개기는 두 가지 일을 섞어 하던 코드를 중간 결과를 사이에 둔 두 단계로 나누는 거예요. 외국어 편지를 먼저 우리말로 옮겨 적고 그다음 내용을 따지면, 각 단계에서 한 가지만 생각하면 돼요.

비유가 깨지는 곳 편지는 한 번 옮기면 끝이지만 코드에선 1단계 결과의 모양이 2단계와의 약속이 돼요. 그래서 중간 데이터는 보통 불변 레코드로 두고, 각 단계는 그 레코드만 보고 따로 고쳐요.

서로 다른 두 가지 일을 한꺼번에 하는 코드를, 중간 데이터 구조를 사이에 둔 연속된 두 단계로 나누는 리팩터링. 고칠 때 한 단계만 생각하면 되게 만든다.

// before: 파싱과 계산이 섞여 있다
const data = orderString.split(/\s+/)
const price = priceList[data[0].split('-')[1]] * parseInt(data[1])
 
// after
const order = parseOrder(orderString) // 1단계: 문자열 → 레코드
const price = priceOrder(order, priceList) // 2단계: 레코드 → 계산
  • 흔한 예: 입력 파싱과 처리, 데이터 계산과 렌더링, 컴파일러의 토큰화(Tokenizing)·파싱(Parsing)·코드 생성(Code Generation)
  • 두 단계 사이의 중간 데이터는 보통 불변 레코드로 두고 굳이 캡슐화하지 않는다
  • 뒤엉킨 변경을 푸는 대표 처방이다
  • 프런트엔드에서 서버 데이터를 화면용 모델로 먼저 바꾼 뒤 렌더링하는 구조나, 선언형 렌더링 함수가 계산 결과만 받게 하는 것도 같은 생각이다

출처: 『리팩터링 2판』 마틴 파울러 (원서 Refactoring, 2nd Edition) · refactoring.com: Split Phase

연결된 개념

이 노트를 가리키는 문서

뜻이 가까운 노트

  • 반복문을 파이프라인으로 바꾸기

    for 반복문을 filter·map·reduce 같은 컬렉션 연산의 연쇄, 즉 컬렉션 파이프라인(Collection Pipeline)으로 바꾸는 리팩터링. 각 원소가 어떤 단계를 거치는지가 위에서 아래로 읽힌다.

  • 리팩터링

    겉으로 보이는 동작은 그대로 둔 채, 코드를 이해하고 고치기 쉽게 내부 구조를 바꾸는 일. 기능을 더하는 일이 아니라 다음 변경을 덜 위험하게 만드는 정리다.

  • 임시 변수를 질의 함수로 바꾸기

    계산 결과를 담아 두던 임시 변수를 그 값을 돌려주는 함수로 바꾸는 리팩터링. 긴 함수를 쪼개기 전 단계로 특히 쓸모 있다.

  • 조건문 분해·통합

    복잡한 조건문의 조건식과 각 분기 본문에 의도를 드러내는 이름을 붙이는 리팩터링(분해, Decompose Conditional), 그리고 결과가 같은 여러 조건 검사를 하나로 묶는 리팩터링(통합, Consolidate Conditional Expression). 조건 코드는 무엇이 일어나는지는 말하지만 왜 그런지는 잘 말하지 않는데, 이름이 그 "왜"를 채운다.

  • 함수·필드 옮기기

    함수나 필드를 더 자연스러운 맥락(모듈·클래스)으로 옮기는 리팩터링. 좋은 설계의 핵심인 모듈성(Modularity), 즉 어딘가를 고칠 때 관련된 작은 부분만 이해하면 되게 하는 능력을 키운다.

보기 옵션