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 플래그가 코드 전반에 흩어져 있다면, 상태 머신 패턴을 적용해 각 단계를 명확히 분리하는 것이 좋음