노트

매개변수 객체 만들기

Introduce Parameter Object

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

쉽게 말하면

매개변수 객체 만들기는 늘 짝지어 다니는 값들을 한 켤레로 묶는 거예요. 신발을 왼짝, 오른짝 따로 건네지 않듯 시작일과 종료일을 '기간' 하나로 넘기면, 매개변수도 줄고 관련 동작이 모일 자리도 생겨요.

비유가 깨지는 곳 아무거나 한 봉지에 담는다고 좋은 건 아니에요. 묶음에 이름과 의미가 있으면 객체로 묶고, 아무 데이터나 담기는 가방이라면 필요한 값을 명시적으로 받는 편이 낫다고 켄트 벡은 말해요.

여러 함수에 늘 함께 넘겨지는 값 묶음(데이터 뭉치, Data Clumps)을 하나의 객체로 묶어 넘기는 리팩터링.

// before
amountInvoiced(startDate, endDate)
amountOverdue(startDate, endDate)
 
// after
type DateRange = { start: Date; end: Date }
amountInvoiced(range)
amountOverdue(range)
  • 매개변수 수가 줄고, 같은 묶음을 쓰는 모든 함수가 같은 이름으로 원소를 부르게 되어 일관성이 생긴다
  • 묶음에 이름이 생기면 "기간 안에 포함되는가" 같은 동작이 모일 자리가 생긴다. 키워 가면 값 객체가 된다
  • 데이터 뭉치인지 판별하려면 값 하나를 빼 본다. 나머지만으로 의미가 없으면 뭉치다

객체 통째로 넘기기(Preserve Whole Object)

레코드에서 값 두어 개를 꺼내 넘기는 대신 레코드 자체를 넘긴다. 함수가 필요한 값이 늘어도 시그니처가 그대로다. 단, 함수가 그 레코드 타입에 의존하게 되므로 서로 다른 모듈이라면 하지 않는다.

반대 방향의 긴장

켄트 벡의 Explicit Parameters(한국어판 "명시적인 매개변수")는 반대를 권한다. 맵을 통째로 받아 안에서 params.a, params.b를 꺼내 쓰는 함수는 무엇이 필요한지 숨기므로, 필요한 값을 명시적으로 받으라는 것이다. 묶음에 이름과 의미가 있으면 객체로, 아무 데이터나 담기는 가방이라면 명시적 인자로 가는 편이 낫다.

긴 매개변수 목록의 다른 처방은 플래그 인수와 코드 냄새 참고.

출처: 『리팩터링 2판』 마틴 파울러 (원서 Refactoring, 2nd Edition) · refactoring.com: Introduce Parameter Object · refactoring.com: Preserve Whole Object · Refactoring.Guru: Introduce Parameter Object · 『켄트 벡의 Tidy First?』 켄트 벡 (원서 Tidy First?)

연결된 개념

이 노트를 가리키는 문서

뜻이 가까운 노트

  • 특이 케이스와 널 객체

    특정 값(가장 흔하게는 null이나 "미확인" 같은 표시값)을 만날 때마다 같은 처리를 하는 코드가 곳곳에 흩어져 있을 때, 그 경우를 대표하는 객체를 하나 만들어 공통 동작을 담는 패턴. null을 대표하면 널 객체(Null Object)라 부르며, 널 객체는 특이 케이스(Special Case)의 한 예다.

  • 변수·컬렉션 캡슐화

    넓은 범위에서 쓰이는 데이터에 직접 접근하지 못하게 하고, 읽고 쓰는 함수를 통해서만 다루게 하는 리팩터링. 데이터를 옮기거나 바꿀 때 고쳐야 할 곳이 접근 함수 한 곳으로 좁아진다.

  • 가변 기본 인자 함정

    파이썬 함수의 기본값은 함수를 정의할 때 한 번 평가되어 그 객체가 계속 재사용된다. 그래서 리스트·딕셔너리 같은 변경 가능한 객체를 기본값으로 쓰면, 호출할 때마다 같은 객체가 공유되어 값이 쌓인다.

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

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

  • 변수 추출하기

    복잡한 표현식의 일부에 이름을 붙여 지역 변수로 빼는 리팩터링. 변수를 추출하고 싶다는 건 그 표현식에 이름을 붙이고 싶다는 뜻이다.

보기 옵션