재현 가능한 예제의 중요성¶
재현 가능한 예제가 중요한 이유¶
최소한의 재현 가능한 예제(MRE)는 버그를 수정하는 데 필수적이다. 문제를 재현할 수 있는 예제가 없으면 유지보수 담당자는 디버깅을 하거나 수정 여부를 테스트할 수 없다. 예제가 최소한의 상태가 아니라면, 즉 문제와 관련 없는 많은 내용이 포함되어 있다면, 유지보수 담당자는 문제의 근본 원인을 파악하는 데 훨씬 더 많은 시간을 소모하게 된다.
재현 가능한 예제 작성 방법¶
재현 가능한 예제를 작성할 때 목표는 다른 사람이 여러분의 예제를 재현할 수 있도록 필요한 모든 컨텍스트를 제공하는 것이다. 여기에는 다음이 포함된다:
- 사용 중인 플랫폼 (예: 운영체제와 아키텍처)
- 관련된 시스템 상태
- uv 버전
- 다른 관련 도구의 버전
- 관련 파일 (
uv.lock
,pyproject.toml
등) - 실행할 커맨드
재현 예제를 최소한으로 유지하려면 가능한 한 많은 의존성, 설정, 파일을 제거한다. 공유하기 전에 반드시 재현 예제를 테스트한다. 재현 과정에서 나오는 상세 로그를 포함하는 것이 좋다. 이 로그는 여러분의 머신에서 중요한 차이를 보일 수 있다. 매우 긴 로그의 경우 Gist를 사용하면 도움이 된다.
아래에서는 재현 가능한 예제를 만들고 공유하기 위한 몇 가지 구체적인 전략을 다룬다.
Tip
Stack Overflow에는 MRE(Minimal Reproducible Example)를 만드는 기본 가이드가 잘 정리되어 있다.
재현 가능한 예제를 위한 전략¶
Docker 이미지¶
Docker 이미지를 작성하는 것은 재현 가능한 예제를 공유하는 가장 좋은 방법이다. Docker 이미지는 완전히 독립적이기 때문에, 재현을 시도하는 시스템의 상태가 문제에 영향을 미치지 않는다.
참고
Docker 이미지를 사용하는 것은 문제가 Linux에서 재현 가능한 경우에만 적합하다. macOS를 사용 중이라면, 이미지가 Linux에서 재현되지 않는지 확인해야 한다. 일부 버그는 특정 운영체제에 종속적일 수 있다. Windows 컨테이너를 Docker로 실행하는 것도 가능하지만, 일반적이지 않다. 이런 종류의 버그는 스크립트로 보고하는 것이 더 적절하다.
uv를 사용해 Docker MRE(Minimal Reproducible Example)를 작성할 때는 uv의 Docker 이미지 중 하나를 시작점으로 사용하는 것이 좋다. 이때, uv의 특정 버전을 명시적으로 고정해야 한다.
FROM ghcr.io/astral-sh/uv:0.5.24-debian-slim
Docker 이미지는 시스템에서 격리되어 있지만, 기본적으로 빌드 시 시스템의 아키텍처를 사용한다. 재현 예제를 공유할 때는 플랫폼을 명시적으로 설정해 재현자가 예상한 동작을 얻을 수 있도록 해야 한다. uv는 linux/amd64
(예: Intel 또는 AMD)와 linux/arm64
(예: Apple M 시리즈 또는 ARM)용 이미지를 제공한다.
FROM --platform=linux/amd64 ghcr.io/astral-sh/uv:0.5.24-debian-slim
Docker 이미지는 명령어로 구성할 수 있는 문제를 재현하는 데 가장 적합하다. 예를 들면 다음과 같다:
FROM --platform=linux/amd64 ghcr.io/astral-sh/uv:0.5.24-debian-slim
RUN uv init /mre
WORKDIR /mre
RUN uv add pydantic
RUN uv sync
RUN uv run -v python -c "import pydantic"
또한, 파일을 이미지에 인라인으로 작성할 수도 있다:
FROM --platform=linux/amd64 ghcr.io/astral-sh/uv:0.5.24-debian-slim
COPY <<EOF /mre/pyproject.toml
[project]
name = "example"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = ["pydantic"]
EOF
WORKDIR /mre
RUN uv lock
많은 파일을 작성해야 한다면, Git 저장소를 생성하고 공개하는 것이 더 좋다. 이 방법을 결합해 저장소에 Dockerfile
을 포함시킬 수도 있다.
Docker 재현 예제를 공유할 때는 빌드 로그를 포함하는 것이 도움이 된다. 캐싱과 화려한 출력을 비활성화해 빌드 단계에서 더 많은 출력을 확인할 수 있다:
docker build . --progress plain --no-cache
스크립트¶
컨테이너에서는 재현할 수 없는 플랫폼 특정 버그를 보고할 때, 버그를 재현하는 데 사용할 수 있는 명령어를 포함한 스크립트를 제공하는 것이 가장 좋다. 예를 들면 다음과 같다:
uv init
uv add pydantic
uv sync
uv run -v python -c "import pydantic"
버그 재현에 여러 파일이 필요한 경우, Git 저장소를 사용해 파일을 공유한다.
스크립트 외에도 실패 시의 상세 로그(-v
플래그 사용)와 전체 오류 메시지를 포함한다.
스크립트가 외부 상태에 의존하는 경우, 해당 정보를 반드시 공유한다. 예를 들어, Windows에서 스크립트를 작성했고 choco
로 설치한 Python 버전을 사용하며 PowerShell 6.2에서 실행했다면, 보고서에 이 정보를 포함한다.
Git 저장소¶
Git 저장소를 공유할 때는 문제를 재현할 수 있는 스크립트나, 더 나은 방법으로 Dockerfile을 포함한다. 스크립트의 첫 단계는 저장소를 복제하고 특정 커밋을 체크아웃하는 것이다:
$ git clone https://github.com/<user>/<project>.git
$ cd <project>
$ git checkout <commit>
$ <오류를 발생시키는 명령어>
GitHub UI나 gh
CLI를 사용하여 새 저장소를 빠르게 생성할 수 있다:
$ gh repo create uv-mre-1234 --clone
Git 저장소를 사용해 문제를 재현할 때는, 문제 재현에 필요하지 않은 파일이나 설정을 제외하여 내용을 최소화한다.