1P by GN⁺ 23시간전 | ★ favorite | 댓글 1개
  • 보고서 생성 애플리케이션 개발 과정에서 –dry-run 옵션을 추가해 실행 결과를 시뮬레이션할 수 있도록 한 사례
  • 이 옵션은 실제 변경 없이 어떤 작업이 수행될지를 출력해, 안전한 테스트와 빠른 피드백을 가능하게 함
  • 개발자는 이를 통해 설정과 접근성, 시스템 상태를 즉시 확인하며 일상적인 검증 도구로 활용
  • 코드 내에서 dryRun 플래그를 확인해야 하는 약간의 복잡성 증가가 단점으로 언급됨
  • 명령형 애플리케이션에서는 –dry-run 기능이 매우 유용하며, 프로젝트 초기에 도입할수록 개발 효율이 높아짐

배경

  • 새로 개발 중인 보고서 생성 애플리케이션은 매일 평일마다 보고서를 생성하고, 이를 압축 후 sftp 서버에 업로드하며 오류 응답을 확인하고 알림 메일을 발송하는 구조
    • 각 단계에서 생성된 파일과 피드백 파일은 단계별로 다른 디렉터리로 이동
  • 개발 초기, Subversion과 여러 리눅스 명령어의 –dry-run 옵션을 떠올려 동일한 기능을 추가
    • 이 옵션은 실제 변경 없이 실행 시 어떤 일이 일어날지를 출력
  • –dry-run 실행 시, 생성될 보고서와 제외될 보고서, 압축 및 이동될 파일, sftp 업로드 및 다운로드 대상 파일을 단계별로 출력

활용과 이점

  • 개발 및 테스트 과정에서 매일 사용될 만큼 유용한 기능
  • 실행 전 상태 점검용으로 사용 시, 설정과 접근성, 시스템 상태를 즉시 확인 가능
    • 실제 변경이 없으므로 안전하게 실행 가능
  • 보고서 상태 파일의 날짜를 변경한 뒤, 해당 보고서가 생성될지 여부를 즉시 확인할 수 있음
    • 실제 보고서 생성에는 시간이 걸리지만, dry-run은 빠른 피드백 제공
  • 전체 시스템 테스트 시에도 빠른 검증 루프를 제공

단점

  • 코드 내에서 dryRun 플래그를 반복적으로 확인해야 하므로 약간의 코드 오염 발생
    • 주요 단계마다 플래그를 검사해 실제 실행 대신 로그만 출력
  • 그러나 이 검사는 깊지 않으며, 보고서 생성 로직 내부에서는 별도 처리가 필요 없음
    • 실행 여부를 결정하는 상위 단계에서만 확인

결론

  • 명령형으로 실행되고 결과를 생성하는 애플리케이션은 –dry-run 옵션과 잘 맞음
    • 반면, 메시지를 기다리는 반응형 애플리케이션에는 적합하지 않음
  • 프로젝트 초기에 추가한 것이 개발 효율 향상에 큰 도움이 되었음
  • 모든 상황에 필요한 기능은 아니지만, 적절한 경우 매우 유용한 도구로 평가됨
Hacker News 의견들
  • 상태를 가지는 시스템과 상호작용할 때는 --dry-run에도 경쟁 조건(race condition) 이 생길 수 있음
    현재 상태에서 툴이 “무엇을 할지” 보여주지만, 실제 실행 시점에는 상황이 달라질 수 있음
    그래서 나는 Terraform의 “plan” 모드 방식을 선호함. 이 모드는 실행 가능한 계획을 만들어두고, 계획 시점의 가정이 바뀌면 중단하거나 롤백할 수 있음
    또한 코드에서 if dry_run:을 여기저기 넣지 않아도 되며, 계획과 실행을 분리해 execute(plan()) 형태로 단순화할 수 있음

    • 예전에 있었던 AWS DNS 장애 사례가 이와 비슷한 경쟁 조건 때문이었음
      DNS Planner와 Enactor 간의 타이밍 문제로 오래된 계획이 최신 계획을 덮어쓰는 일이 발생했음
      관련 내용은 이전 HN 스레드에서도 다뤄졌음
    • 이렇게 되면 결국 컴파일러(명세→계획)가상머신(계획→실행) 을 구현하는 셈이 됨
    • Terraform이나 Ansible 같은 인프라 도구에는 이상적이지만, 단순 리포팅 툴에는 과도한 복잡성을 초래할 수 있음
      계획 모드를 만들려면 도메인 전용 언어나 데이터 구조가 필요하기 때문임
    • 나도 민감한 파일을 수정하는 스크립트를 만들고 있는데, 이 방식을 적용 중임
      (1) 파일 시스템 상태를 캡처해 계획을 저장 → (2) 상태가 변하지 않았는지 확인 후 실행 및 로그 기록 → (3) 이전 상태와 비교해 데이터 손실 여부 검증
      세 단계를 각각의 스크립트나 플래그로 분리해 사용 중임
    • 그렇다면 rm 명령어에 이런 계획 모드를 어떻게 적용할 수 있을지 궁금함
  • 어떤 도구에 --dry-run이 없을 때는 직접 만들어 쓰기도 함
    예를 들어 복잡한 sed 명령을 실행하기 전, diff를 이용해 변경 내용을 미리 비교함
    diff -u <(echo "hello") <(echo "hello" | sed "s/hello/hi/g") 같은 식으로 차이를 확인할 수 있음
    관련 글은 내 블로그에 정리해둠

  • --dry-run 패턴을 좋아하지만, 드라이 경로의 코드가 실제 경로와 동일하게 동작해야 함
    단순히 “무엇을 할 것이다”만 출력하고 실제 로직을 건너뛰면, 실제 실행 시 버그를 놓칠 수 있음
    데이터베이스 쓰기나 API 호출 직전까지는 동일하게 실행되도록 해야 함

    • 하지만 어떤 사람은 이것이 통합 테스트와 드라이런을 혼동하는 것이라고 봄
      드라이런은 “무엇이 일어날지”를 보여주는 것이고, 실제 테스트는 별도의 영역임
  • 나는 반대로 --commit이나 --execute 플래그를 두고, 기본 실행은 읽기 전용(dry) 으로 두는 방식을 선호함
    이렇게 하면 실수로 실제 변경을 일으킬 가능성이 줄어듦

    • 지난 8년간 이 방식을 써왔는데, --commit을 명시해야만 변경이 일어나므로 안전했음
      반면 --dry-run을 깜빡하고 실행해 사고가 난 적은 많았음
    • 디렉터리 중복 제거 도구도 이 패턴을 따름
      기본은 비교만 하고, --execute를 써야 실제 하드링크로 교체함
    • 예전에 썼던 툴 중에는 실제 실행 전 특정 문구를 입력해야 하는 것도 있었음
      이런 확인 절차는 실수를 줄이는 데 효과적임
    • 개인적으로는 --wet-run 같은 플래그도 좋아함. 상황에 따라 반대 의미의 플래그가 더 직관적일 때도 있음
    • 최근 만든 스크립트는 기본이 읽기 전용이고, 실제 삭제를 하려면 DELETE-ACCOUNT를 직접 입력해야 함
      지금까지 단 한 번도 실수로 계정을 삭제한 적이 없음
  • 코드 오염을 막으려면 지속성(persistence) 을 주입 가능한 전략으로 분리해야 함
    if dry_run:을 여기저기 넣는 건 좋지 않음
    오히려 프로덕션 실행을 --wet-run으로 명시하는 편이 안전함

    • 애플리케이션의 행동을 명시적으로 모델링하고, 이를 중앙에서 처리하도록 하면 좋음
      이렇게 하면 드라이런 여부를 한 곳에서만 판단할 수 있음 — “functional core, imperative shell” 스타일로
    • 하지만 매번 rm --wet-run tempfile.tmp처럼 입력하는 건 번거로움
      기본은 실제 실행으로 두고, 대신 --undo 옵션으로 마지막 작업을 되돌릴 수 있으면 좋겠음
    • --wet-run이라는 이름은 마음에 들지 않지만, 기본을 dry-run으로 두고 --no-dry-run을 명시해야 변경이 일어나게 하는 방식도 써봤음
      서비스라면 실행 환경(dev/prod)에 따라 자동으로 안전 모드를 선택하도록 하는 게 이상적임
    • 이런 경우 디자인 패턴을 활용하면 구조를 깔끔하게 유지할 수 있음
  • 글에서 “초기에 --dry-run을 추가했는데 의외로 유용했다”고 했는데,
    사실 이런 플래그는 AI 코딩 에이전트(예: Claude) 가 자동으로 제안하는 경우가 많음
    요즘은 많은 CLI 도구가 비슷한 패턴을 가지는 이유가 이런 에이전트 기반 코드 수렴 현상 때문일 수도 있음

    • 하지만 작성자가 Subversion의 --dry-run에서 영감을 받았다고 직접 언급했으니, 충분히 설득력 있는 이유로 보임
  • 나는 CLI 유틸리티에 --really 플래그를 추가해, 기본은 읽기 전용으로 두는 편임
    실수를 방지하기 위해 의도적 확인 절차를 요구하는 것임

    • 예전에 --i-meant-that 플래그를 둔 명령도 있었음.
      원격 머신을 삭제하는 명령인데, 기본은 10초간 대기하며 취소할 기회를 줌
      다행히 이 플래그가 잘못 쓰인 적은 없었음
  • PowerShell의 멋진 점 중 하나는 [CmdletBinding(SupportsShouldProcess)] 한 줄만 추가하면
    자동으로 -WhatIf 드라이런 기능을 쓸 수 있다는 것임. 매우 편리한 기능

    • 게다가 -Confirm도 함께 활성화되고, ShouldProcess 함수로 사용자 확인 임계값과 상호작용할 수 있음. 정말 멋진 설계임
  • 내가 관리하는 내부 CLI에서는 if not dry_run:REST API 호출부 안에 넣음
    이렇게 하면 실제 호출 대신 CURL 명령 로그를 남겨서 어떤 요청이 나갈지 확인할 수 있음
    하지만 API 간 연동이 복잡해지면 시뮬레이션이 어려워지고, 단순한 if not dry_run:보다 훨씬 복잡해짐

    • 가능한 한 한 곳에서만 실제 동작을 수행하도록 구조화하면 코드 오염을 막을 수 있음
      나도 자동화 파이프라인용 CLI를 많이 유지보수하는데, 이 패턴을 거의 모든 도구에 적용함
    • 하지만 콘솔 툴에 REST를 과하게 쓰는 건 비효율적이라는 의견도 있음
      로컬 도구부터 제대로 만드는 게 중요하다는 주장임
  • --dry-run 플래그가 코드 전반에 흩어져 있다면, 상태 머신 패턴을 적용해 각 단계를 명확히 분리하는 것이 좋음