1 pontos por GN⁺ 2026-02-02 | 1 comentários | Compartilhar no WhatsApp
  • Um caso em que, no processo de desenvolvimento de um aplicativo de geração de relatórios, foi adicionada a opção --dry-run para permitir simular o resultado da execução
  • Essa opção mostra quais ações seriam executadas sem fazer alterações reais, permitindo testes seguros e feedback rápido
  • Com isso, o desenvolvedor consegue verificar imediatamente configurações, acessibilidade e o estado do sistema, usando o recurso como uma ferramenta de verificação do dia a dia
  • Como desvantagem, menciona-se um leve aumento de complexidade por ser necessário verificar a flag dryRun dentro do código
  • Em aplicativos imperativos, a funcionalidade --dry-run é muito útil, e quanto mais cedo ela for introduzida no projeto, maior tende a ser a eficiência no desenvolvimento

Contexto

  • O novo aplicativo de geração de relatórios em desenvolvimento tem uma estrutura que gera relatórios todos os dias úteis, compacta esses arquivos, faz upload para um servidor sftp, verifica respostas de erro e envia e-mails de notificação
    • Os arquivos gerados e os arquivos de feedback de cada etapa são movidos para diretórios diferentes conforme a fase do processo
  • No início do desenvolvimento, ao lembrar do Subversion e da opção --dry-run de vários comandos Linux, foi adicionada a mesma funcionalidade
    • Essa opção mostra o que aconteceria na execução sem realizar mudanças reais
  • Ao executar com --dry-run, são exibidos por etapa os relatórios que seriam gerados e os que seriam excluídos, os arquivos que seriam compactados e movidos, e os arquivos alvo de upload e download via sftp

Uso e benefícios

  • É uma funcionalidade tão útil que passou a ser usada diariamente durante o desenvolvimento e os testes
  • Quando usada para verificar o estado antes da execução, permite confirmar imediatamente configurações, acessibilidade e o estado do sistema
    • Como não há mudanças reais, pode ser executada com segurança
  • Após alterar a data do arquivo de estado do relatório, é possível confirmar imediatamente se aquele relatório será gerado ou não
    • A geração real do relatório leva tempo, mas o dry-run fornece feedback rápido
  • Mesmo em testes do sistema completo, ele oferece um ciclo rápido de validação

Desvantagens

  • Como é preciso verificar repetidamente a flag dryRun dentro do código, ocorre uma pequena poluição no código
    • Em cada etapa principal, a flag é verificada para exibir apenas logs em vez de executar de fato
  • No entanto, essa verificação não é profunda, e não é necessário tratamento separado dentro da lógica de geração de relatórios
    • A checagem ocorre apenas nas camadas superiores que decidem se a execução acontecerá ou não

Conclusão

  • Aplicativos executados de forma imperativa e que produzem resultados combinam bem com a opção --dry-run
    • Em contrapartida, ela não é adequada para aplicativos reativos que ficam aguardando mensagens
  • O fato de ter sido adicionada no início do projeto ajudou muito a melhorar a eficiência do desenvolvimento
  • Não é uma funcionalidade necessária em todos os casos, mas, quando apropriada, é uma ferramenta extremamente útil

1 comentários

 
GN⁺ 2026-02-02
Comentários do Hacker News
  • Ao interagir com sistemas com estado, até um --dry-run pode sofrer com condições de corrida (race conditions)
    A ferramenta mostra “o que vai fazer” com base no estado atual, mas, no momento da execução real, a situação pode já ter mudado
    Por isso, eu prefiro a abordagem do modo “plan” do Terraform. Esse modo cria um plano executável e, se as suposições feitas no momento do planejamento mudarem, ele pode interromper ou fazer rollback
    Além disso, não é preciso espalhar if dry_run: pelo código, e dá para simplificar separando planejamento e execução no formato execute(plan())

    • Houve um antigo incidente de DNS na AWS causado por uma condição de corrida parecida
      Por um problema de timing entre o DNS Planner e o Enactor, um plano antigo acabou sobrescrevendo o plano mais recente
      Isso também foi discutido em um thread anterior no HN
    • No fim, isso significa implementar um compilador (especificação → plano) e uma máquina virtual (plano → execução)
    • É ideal para ferramentas de infraestrutura como Terraform ou Ansible, mas pode introduzir complexidade excessiva em ferramentas simples de geração de relatórios
      Afinal, criar um modo de planejamento exige uma linguagem específica de domínio ou uma estrutura de dados própria
    • Eu também estou criando um script que modifica arquivos sensíveis e estou aplicando essa abordagem
      (1) capturar o estado do sistema de arquivos e salvar o plano → (2) verificar se o estado não mudou, então executar e registrar logs → (3) comparar com o estado anterior para validar se houve perda de dados
      Estou usando essas três etapas separadas em scripts ou flags diferentes
    • Nesse caso, fico curioso sobre como aplicar esse modo de planejamento ao comando rm
  • Quando alguma ferramenta não tem --dry-run, às vezes eu mesmo monto algo equivalente
    Por exemplo, antes de executar um comando sed mais complexo, uso diff para comparar previamente as mudanças
    Dá para verificar a diferença com algo como diff -u <(echo "hello") <(echo "hello" | sed "s/hello/hi/g")
    Reuni mais exemplos no meu blog

  • Eu gosto do padrão --dry-run, mas o código do caminho dry precisa se comportar igual ao caminho real
    Se ele só imprimir “o que faria” e pular a lógica de verdade, bugs podem passar despercebidos na execução real
    Ele deveria rodar da mesma forma até imediatamente antes de uma escrita no banco de dados ou de uma chamada de API

    • Mas há quem veja isso como uma confusão entre teste de integração e dry-run
      O dry-run serve para mostrar “o que aconteceria”, enquanto teste real é outro assunto
  • Eu prefiro o contrário: ter uma flag --commit ou --execute, e deixar a execução padrão como somente leitura (dry)
    Assim, a chance de causar mudanças reais por acidente diminui

    • Uso esse padrão há 8 anos, e ele tem sido seguro porque só há alteração quando --commit é explicitado
      Já houve muitos acidentes por executar algo esquecendo do --dry-run
    • Minha ferramenta de deduplicação de diretórios também segue esse padrão
      Por padrão ela só compara, e só substitui por hardlinks quando se usa --execute
    • Algumas ferramentas que usei no passado exigiam digitar uma frase específica antes da execução real
      Esse tipo de etapa de confirmação é eficaz para reduzir erros
    • Pessoalmente, também gosto de flags como --wet-run. Dependendo do caso, uma flag com o sentido oposto pode ser mais intuitiva
    • Um script que fiz recentemente é somente leitura por padrão, e para realmente apagar algo é preciso digitar DELETE-ACCOUNT
      Até hoje nunca apaguei uma conta por engano
  • Para evitar poluir o código, a persistência deve ser separada como uma estratégia injetável
    Não é uma boa ideia espalhar if dry_run: por toda parte
    Na verdade, pode ser mais seguro exigir explicitamente a execução de produção com --wet-run

    • O ideal é modelar explicitamente o comportamento da aplicação e tratá-lo de forma centralizada
      Assim, a decisão sobre ser dry-run ou não fica em um único lugar — no estilo “functional core, imperative shell”
    • Mas ter que digitar algo como rm --wet-run tempfile.tmp toda vez seria incômodo
      Talvez fosse melhor deixar a execução real como padrão e, em vez disso, ter uma opção --undo para desfazer a última ação
    • Não gosto muito do nome --wet-run, mas já usei uma abordagem em que o padrão é dry-run e só há mudança ao explicitar --no-dry-run
      Em serviços, o ideal seria escolher automaticamente um modo seguro conforme o ambiente de execução (dev/prod)
    • Nesses casos, usar padrões de projeto pode ajudar a manter a estrutura limpa
  • O texto dizia que “adicionou --dry-run logo no começo e isso acabou sendo surpreendentemente útil”,
    mas, na prática, esse tipo de flag muitas vezes é sugerido automaticamente por agentes de codificação com IA (ex.: Claude)
    Talvez o motivo de tantas ferramentas CLI hoje terem um padrão parecido seja esse fenômeno de convergência de código baseado em agentes

    • Mas como o autor mencionou explicitamente que se inspirou no --dry-run do Subversion, isso parece uma explicação bem convincente
  • Eu costumo adicionar uma flag --really em utilitários CLI e deixar o padrão como somente leitura
    É uma forma de exigir uma etapa deliberada de confirmação para evitar erros

    • Já vi também um comando com a flag --i-meant-that
      Era um comando para apagar uma máquina remota e, por padrão, ele esperava 10 segundos para dar chance de cancelar
      Felizmente, essa flag nunca foi usada de forma errada
  • Uma das coisas legais do PowerShell é que, se você adicionar uma única linha [CmdletBinding(SupportsShouldProcess)],
    já pode usar automaticamente o recurso de dry-run com -WhatIf. É uma funcionalidade muito conveniente

    • Além disso, -Confirm também é ativado, e com a função ShouldProcess dá para interagir com o limiar de confirmação do usuário. É um design realmente elegante
  • No CLI interno que eu mantenho, coloco if not dry_run: dentro da parte que faz as chamadas à API REST
    Assim, no lugar da chamada real, eu registro o comando CURL para verificar que requisição seria enviada
    Mas, quando a integração entre APIs fica mais complexa, a simulação se torna difícil e muito mais complicada do que um simples if not dry_run:

    • Estruturar o sistema para que a ação real aconteça em apenas um ponto ajuda a evitar poluição no código
      Eu mantenho muitos CLIs para pipelines de automação, e aplico esse padrão em quase todas as ferramentas
    • Mas também há quem ache ineficiente depender demais de REST em ferramentas de console
      A ideia é que o mais importante é construir primeiro boas ferramentas locais
  • Se a flag --dry-run estiver espalhada por todo o código, pode ser uma boa aplicar o padrão de máquina de estados para separar claramente cada etapa