상태를 가지는 시스템과 상호작용할 때는 --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 플래그가 코드 전반에 흩어져 있다면, 상태 머신 패턴을 적용해 각 단계를 명확히 분리하는 것이 좋음
Hacker News 의견들
상태를 가지는 시스템과 상호작용할 때는
--dry-run에도 경쟁 조건(race condition) 이 생길 수 있음현재 상태에서 툴이 “무엇을 할지” 보여주지만, 실제 실행 시점에는 상황이 달라질 수 있음
그래서 나는 Terraform의 “plan” 모드 방식을 선호함. 이 모드는 실행 가능한 계획을 만들어두고, 계획 시점의 가정이 바뀌면 중단하거나 롤백할 수 있음
또한 코드에서
if dry_run:을 여기저기 넣지 않아도 되며, 계획과 실행을 분리해execute(plan())형태로 단순화할 수 있음DNS Planner와 Enactor 간의 타이밍 문제로 오래된 계획이 최신 계획을 덮어쓰는 일이 발생했음
관련 내용은 이전 HN 스레드에서도 다뤄졌음
계획 모드를 만들려면 도메인 전용 언어나 데이터 구조가 필요하기 때문임
(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) 으로 두는 방식을 선호함이렇게 하면 실수로 실제 변경을 일으킬 가능성이 줄어듦
--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 도구가 비슷한 패턴을 가지는 이유가 이런 에이전트 기반 코드 수렴 현상 때문일 수도 있음
--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를 많이 유지보수하는데, 이 패턴을 거의 모든 도구에 적용함
로컬 도구부터 제대로 만드는 게 중요하다는 주장임
--dry-run플래그가 코드 전반에 흩어져 있다면, 상태 머신 패턴을 적용해 각 단계를 명확히 분리하는 것이 좋음