노트

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

Replace Loop with Pipeline

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

쉽게 말하면

반복문을 파이프라인으로 바꾸기는 한 사람이 모든 일을 뒤섞어 하던 작업을 '거르기, 바꾸기, 모으기' 순서의 컨베이어 벨트로 펼치는 거예요. 물건이 어떤 단계를 거치는지 위에서 아래로 읽혀요.

비유가 깨지는 곳 단계를 나누면 데이터를 여러 번 돌아 느려질 것 같지만 대부분 무시할 수준이에요. 다만 큰 데이터에서 map 안에 find를 넣는 식의 중첩은 복잡도 자체가 커져요.

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

// before
const names: string[] = []
for (const p of people) {
  if (p.job === 'programmer') names.push(p.name)
}
 
// after
const names = people.filter(p => p.job === 'programmer').map(p => p.name)

먼저 반복문 쪼개기(Split Loop)

한 반복문이 두 가지 일(예: 합계와 평균)을 동시에 하면 고칠 때마다 둘 다 이해해야 한다. 반복문을 복제해 하나에 한 가지 일만 시키면, 각 반복문을 함수로 뽑거나 파이프라인으로 바꾸기 쉬워진다.

  • 반복을 두 번 돌면 느려질까 걱정되지만 대부분 무시할 수준이다. 리팩터링과 최적화를 구분하고, 정말 병목이면 측정한 뒤 다시 합친다(섣부른 최적화, 핫 패스)
  • 다만 큰 데이터에서 map 안에 find를 넣는 식의 중첩은 복잡도 자체가 커진다(빅오 표기법)
  • 인덱스 변수가 사라져 구성요소가 줄고, 선언형 코드에 가까워진다

출처: 『리팩터링 2판』 마틴 파울러 (원서 Refactoring, 2nd Edition) · refactoring.com: Replace Loop with Pipeline · refactoring.com: Split Loop · Martin Fowler: Collection Pipeline

연결된 개념

이 노트를 가리키는 문서

뜻이 가까운 노트

  • 단계 쪼개기

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

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

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

  • 리팩터링 기법 카탈로그

    리팩터링 기법을 무엇을 정리하는지에 따라 묶어 본 지도. 기법마다 거의 항상 반대 방향 기법이 짝으로 있어서(추출↔인라인, 올리기↔내리기) 상황에 따라 양쪽으로 오간다. 아래 묶음은 Refactoring.Guru 카탈로그(1판 기반)의 분류를 따랐고, 기법 이름은 2판 기준으로 적었다.

  • 리팩터링

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

  • 조건문 분해·통합

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

보기 옵션