1 pontos por GN⁺ 2023-11-16 | 1 comentários | Compartilhar no WhatsApp

Elevar condicionais para fora da função

  • Se houver uma condicional if dentro de uma função, considere movê-la para o chamador (caller).
  • Em vez de a função verificar internamente as pré-condições e "não fazer nada" quando elas não forem atendidas, faça o chamador verificar as pré-condições para que o sistema de tipos garanta que elas foram satisfeitas.
  • Em especial, ao "elevar" as pré-condições, pode-se reduzir a quantidade total de verificações, e essa é uma das motivações desta regra.

Rebaixar laços de repetição

  • Regra vinda do pensamento orientado a dados: introduz o conceito de "lote" (batch) do objeto, toma as operações em lote como caso padrão e trata a versão escalar como um caso especial da versão em lote.
  • O principal benefício é o ganho de desempenho, pois é possível diluir o custo inicial e ter flexibilidade na ordem de processamento.
  • Por exemplo, na multiplicação de polinômios baseada em FFT, avaliar polinômios em vários pontos ao mesmo tempo pode ser mais rápido do que avaliações individuais.

Opinião do GN⁺

  • O ponto mais importante deste texto são duas regras de programação para melhorar o desempenho e a clareza do código no desenvolvimento de software: "elevar condicionais" e "rebaixar laços de repetição".
  • Essas regras ajudam a aumentar a legibilidade do código, otimizar o desempenho e reduzir a possibilidade de bugs.
  • Como oferece insights sobre como lidar com a complexidade da engenharia de software e escrever código eficiente, este texto é interessante e útil para muitos desenvolvedores.

1 comentários

 
GN⁺ 2023-11-16
Comentários do Hacker News
  • Há quem ache surpreendente a reação contrária aos conselhos sobre design orientado a dados. Como a maioria dos usuários de fóruns escreve aplicações web, esse conselho pode parecer sem sentido. Se você não precisa pensar em cache de instruções no trabalho do dia a dia, deve ignorar esse conselho. Consultar "Typical C++ Bullshit", de Mike Acton, pode ajudar a entender a importância desse conselho.
  • Há a opinião de que os programadores se preocupam em deixar o código bonito em "pequenas unidades", mas não se preocupam o suficiente com o projeto adequado de toda a base de código. Se uma função tem um bom nome, uma boa interface, um propósito claro, está devidamente documentada e não usa efeitos colaterais em excesso, então não se deveria dar tanta importância ao fato de a função ser bagunçada ou à disposição de if e for.
  • Segundo alguém que começou a programar na área científica, pequenas otimizações importam. Usar a ordem errada em loops for pode reduzir o tempo de execução de uma simulação de 1 semana para 1 hora. Quem tem esse tipo de formação tende a otimizar intuitivamente a ordem de for e if.
  • Há a opinião de que, quando existe um "container", em vez de escrever funções para o container, deve-se escrever funções para a "Thing" em nível de domínio que ele contém. Isso torna o código mais flexível e separa com mais clareza o domínio central dos interesses da aplicação.
  • Há desvantagens em mover if para cima, pois isso faz com que as pré-condições e pós-condições da função deixem de ser visíveis diretamente na definição da função. Em projetos grandes, essas funções podem ser reutilizadas fora do contexto pretendido, causando bugs. Usar um framework de contratos pode ser uma solução, mas isso exige escrever as condições duas vezes, nos contratos e no código.
  • Em um exemplo com a linguagem Rust, o sistema de tipos robusto de Rust evita a necessidade de programação defensiva exigida em outras linguagens. Não é desejável que um programador em C não valide a validade de um ponteiro passado para uma função e acabe causando uma desreferenciação de NULL. Alguns if devem ficar no topo da função, não no final, e os erros devem ser propagados corretamente.
  • Há a opinião de que o artigo parecia levar a um exemplo específico de código, mas no fim não foi isso que aconteceu. Em vez do exemplo de código esperado, foi apresentado outro exemplo.
  • Sem contexto adequado, esse conselho pode ser estranho e até ruim. Loops for e instruções if são ambos operações de controle de fluxo, então algumas afirmações do artigo parecem sem sentido. A alegação sobre desempenho é a mais forte, mas, como preocupação em relação a conselhos gerais, deveria ser considerada por último.
  • Há a opinião de que não se pode ter certeza de que essas regras gerais possam ser aplicadas a código real. Muitas vezes essas regras são vistas como dogmas equivocados, e programadores jovens podem interpretá-las mal e acabar escrevendo código pior. Não é possível mover if para cima quando a condição depende do operador walrus.
  • Há a opinião de que mover o if de pré-condição para o chamador é uma ideia terrível. Em casos especiais, pode ser uma boa ideia, mas no caso geral isso não é desejável. Em bibliotecas, as pré-condições devem ser verificadas nas fronteiras externas para que a implementação interna possa seguir sem depender de suposições internas. Depender de verificações feitas pelo chamador anula esse propósito.