[개발 깨알 상식_Tips]/[바이브코딩 Tips] / 기본값 패치를 무력화한 호출부의 명시적 인자.md

기본값 패치를 무력화한 호출부의 명시적 인자

조회

2026년 7월 13일 | 바이브코딩 Tips


함수 기본값보다 호출부의 명시적 인자가 우선해 실제 실행값이 바뀌지 않는 경로
정의부의 기본값을 바꿔도 래퍼가 값을 직접 넘기면 실제 실행에는 그 값이 계속 적용된다.

5초로 고쳤는데 30초를 기다린 장면

함수의 timeout 기본값을 30초에서 5초로 바꾼 패치가 들어왔는데, 실제 API 호출은 여전히 30초를 기다렸다. 코딩 에이전트가 수정한 함수의 단위 테스트도 통과했고 diff도 한 줄뿐이었다. 처음에는 캐시나 배포 지연을 의심했지만 원인은 더 단순했다. 운영 진입점 앞의 래퍼가 timeout=30을 명시적으로 넘기고 있었다.

기본값은 인자가 생략됐을 때만 쓰인다. 호출부가 값을 직접 넘기면 정의부의 기본값은 후보에서 빠진다. 그런데 에이전트에게 “기본 timeout을 줄여 달라”고 말하면 수정 위치가 함수 시그니처로 너무 쉽게 고정된다. 테스트 역시 인자를 생략한 직접 호출만 확인하면 초록색이 된다. 패치가 맞는 줄과 실제 요청이 지나는 줄은 다를 수 있다.

정의부 한 줄은 동작 계약의 전부가 아니다

나는 기본값 변경을 작은 설정 수정으로 보지 않게 됐다. 같은 함수라도 CLI, 웹 API, 배치 작업, 테스트 fixture가 서로 다른 값을 넘길 수 있기 때문이다. 어떤 호출부는 값을 생략하고, 어떤 호출부는 환경변수에서 읽은 값을 넣고, 오래된 래퍼는 과거 기본값을 숫자로 복사해 둔다. 정의부만 보면 기본값은 하나지만 실행 경로에는 사실상 여러 기본값이 존재한다.

특히 코드가 여러 계층으로 감싸져 있으면 이 복제가 잘 보이지 않는다. 상위 함수가 받은 옵션을 그대로 전달하거나, 설정 객체를 펼치거나, 빈 값을 fallback으로 바꾸는 과정에서 최종 인자가 결정된다. 그래서 나는 에이전트의 완료 보고에 “기본값을 5초로 변경”만 있으면 아직 보류한다. 어느 진입점에서 인자를 생략했고, 어느 경로가 값을 덮어썼는지가 함께 보여야 실제 계약을 바꿨다고 판단한다.

호출부 검색은 이름보다 전달 모양을 본다

첫 확인은 함수 이름 검색이지만 거기서 끝내지 않는다. 직접 호출, 키워드 인자, 설정 객체, 래퍼 함수, 의존성 주입처럼 값이 들어오는 모양을 나눠 본다. Python이라면 timeout= 같은 키워드 호출뿐 아니라 **options와 설정 dataclass를 같이 확인한다. TypeScript라면 객체 펼침 순서 때문에 기본 옵션 뒤의 사용자 옵션이 다시 값을 덮을 수도 있다.

def fetch(url, timeout=5):
    ...

def fetch_for_job(url):
    return fetch(url, timeout=30)

이 예제에서 직접 호출 테스트는 새 기본값을 검증하지만 배치 작업의 실제 경로는 검증하지 못한다. 호출부가 많다면 전부 읽기보다 먼저 사용자에게 노출된 진입점과 장애가 났던 입력을 고른다. 검색 결과의 개수보다 원래 문제를 재현한 경로가 어떤 값을 최종 전달하는지가 중요하다.

테스트는 생략 호출과 명시 호출을 나눈다

기본값 패치에는 최소 두 종류의 테스트가 필요했다. 하나는 인자를 생략했을 때 5초가 적용되는지 보는 정의부 테스트다. 다른 하나는 실제 래퍼를 통해 들어왔을 때 최종 timeout이 무엇인지 보는 통합에 가까운 테스트다. 두 번째 테스트가 없으면 “기본값은 바뀌었다”와 “사용자 동작이 바뀌었다”를 같은 문장으로 오해하기 쉽다.

여기에 의도적인 명시 인자도 하나 남긴다. 모든 30초가 낡은 값은 아닐 수 있다. 대용량 다운로드나 느린 외부 서비스처럼 긴 대기가 필요한 경로도 있다. 그래서 검색된 숫자를 기계적으로 5로 치환하지 않고, 각 호출부를 새 기본값을 따라갈 경로, 업무상 값을 고정할 경로, 아직 이유를 확인하지 못한 경로로 나눈다. 이 분류가 없으면 수정 반경만 커지고 예외의 근거는 사라진다.

최종 인자값을 한 번 관찰한다

코드 읽기만으로 전달 경로가 길어지면 실제 진입점에서 값을 한 번 관찰하는 편이 빠르다. 테스트 double이나 짧은 debug 로그로 하위 함수가 받은 timeout을 확인하면 된다. 중요한 것은 로그를 영구 기능으로 남기는 게 아니라, 원래 장애 입력이 어느 값으로 도착하는지 증거를 잡는 것이다. 값이 30이라면 정의부 패치가 운영 경로에 닿지 않은 것이고, 5인데도 30초를 기다린다면 그때 네트워크 재시도나 별도 클라이언트 제한을 본다.

이 순서를 지키면 원인 범위가 빨리 줄어든다. 처음부터 캐시, 배포, 재시도 정책을 모두 열지 않고 “최종 인자가 바뀌었는가”부터 자른다. 나는 에이전트에게도 패치 설명보다 관찰값을 먼저 요구한다. 실패 입력, 실제 진입점, 하위 함수가 받은 값 세 가지가 맞으면 다음 조사도 추측이 아니라 확인에서 시작한다.

설정값의 출처도 같이 남긴다

명시적 인자가 코드에 숫자로 박혀 있지 않으면 더 헷갈린다. 환경변수, YAML, 요청 파라미터, 데이터베이스 설정이 래퍼를 거쳐 들어오면 검색 결과에는 timeout=config.timeout 한 줄만 보인다. 이때 나는 값만 출력하지 않고 출처도 같이 본다. 예를 들어 timeout=30, source=JOB_TIMEOUT처럼 관찰하면 오래된 배포 설정이 새 코드 기본값을 계속 덮는 장면이 바로 드러난다.

설정 계층에는 보통 우선순위가 있다. 사용자 입력이 프로젝트 설정을 덮고, 프로젝트 설정이 환경변수를 덮고, 아무 값도 없을 때 코드 기본값이 적용되는 식이다. 그런데 문서에는 “기본 5초”라고만 쓰고 이 우선순위를 적지 않으면, 다음 에이전트는 30초를 모두 버그로 오해할 수 있다. 나는 그래서 변경 기록에 기본값이 적용되는 조건그보다 우선하는 입력을 한 줄씩 남긴다.

민감한 설정을 로그로 남길 때는 값 전체를 무조건 찍지 않는다. timeout처럼 안전한 숫자는 그대로 볼 수 있지만 토큰, URL의 인증 정보, 사용자 데이터가 섞인 옵션은 출처 이름과 존재 여부만 기록한다. 목표는 운영 로그를 늘리는 것이 아니라 최종 값이 어떤 층에서 결정됐는지 확인하는 것이다. 출처를 알면 수정 위치도 정의부, 래퍼, 배포 설정 중 하나로 좁아진다.

완료 기준은 수정 줄이 아니라 호출 경로다

이런 패치의 완료 조건은 함수 시그니처가 원하는 숫자를 갖는 것이 아니다. 인자를 생략하는 경로는 새 기본값을 받고, 의도적으로 값을 고정한 경로는 이유가 남아 있으며, 원래 문제를 일으킨 진입점의 관찰값이 바뀌어야 한다. 테스트도 직접 호출 하나가 아니라 실제 래퍼를 한 번 통과해야 한다.

코딩 에이전트는 요청에서 가장 선명한 단어를 수정 위치로 잡는 경향이 있다. “기본값”이라고 말하면 정의부를, “timeout”이라고 말하면 숫자를 먼저 찾는다. 나는 그래서 요청 끝에 “실제 사용자 진입점에서 최종 전달값까지 확인”을 붙인다. 한 줄 패치를 불필요하게 키우려는 게 아니라, 한 줄이 어느 경로에서 효력을 갖는지 확인하려는 것이다. 기본값 변경은 작아 보여도 호출부가 값을 들고 있으면 실제 동작은 전혀 움직이지 않는다.

댓글

홈으로 돌아가기

검색 결과

"" 검색 결과입니다.