Neste artigo de 2003 de Stephen Figgins no linuxdevcenter.com , o BitTorrent de Bram Cohen é descrito como usando o padrão de design "Fix Everything".
Uma abordagem menos comum que dificulta a compreensão do BitTorrent, mas é digna de estudo, é o uso de idempotência de Cohen. Um processo é idempotente ao aplicá-lo mais de uma vez, não causa mais alterações. Cohen diz que usa um padrão de design que ele chama de "Consertar tudo", uma função que pode reagir a várias mudanças sem realmente notar o que tudo isso pode mudar. Ele explica: "você observa o evento que aconteceu, depois chama a função de corrigir tudo, que é escrita dessa maneira muito idempotente, e apenas limpa o que quer que esteja acontecendo e recalcula tudo do zero". Embora a idempotência facilite alguns cálculos difíceis, ela torna as coisas um pouco complicadas. Nem sempre é claro o que uma chamada vai mudar, se é que alguma coisa. Você não precisa saber com antecedência. Você é livre para chamar a função,
Isso parece muito bom em face disso.
No entanto, parece-me que chamar uma função idempotente de "consertar tudo" melhoraria a robustez do sistema ao custo da eficiência e potencialmente danificaria o sistema que o continha (que pode preferir processos que planejem e executem com cuidado).
Mas não posso dizer que já o usei antes. Também não consigo encontrar a fonte do aplicativo on-line (mas achei esse que afirma ser baseado nele). Também não consigo encontrar referências a ele fora deste artigo (e considero meu google-fu muito bom), mas encontrei uma entrada para "Idempotent Capability" no SOApatterns.org .
Essa idéia é mais conhecida por outro nome?
O que é o padrão de design "Corrigir tudo"? Quais são seus prós e contras?
fonte
This sounds quite nice on the face of it.
Realmente? Parece horrível para mim!Respostas:
Digamos que você tenha uma página HTML bastante complicada - se você escolher algo em uma lista suspensa, outro controle poderá aparecer ou os valores em um terceiro controle poderão ser alterados. Há duas maneiras de abordar isso:
Escreva um manipulador separado, para cada controle, que responda a eventos nesse controle e atualize outros controles conforme necessário.
Escreva um único manipulador que analise o estado de todos os controles na página e apenas corrija tudo .
A segunda chamada é "idempotente" porque você pode chamá-la repetidamente e os controles sempre serão organizados corretamente. Considerando que a primeira chamada (s) pode ter problemas se uma chamada for perdida ou repetida, por exemplo, se um dos manipuladores executar uma alternância.
A lógica da segunda chamada seria um pouco mais obscura, mas você só precisa escrever um manipulador.
E você sempre pode usar as duas soluções, chamando a função "consertar tudo" conforme necessário "apenas para estar do lado seguro".
A segunda abordagem é especialmente agradável quando o estado pode vir de diferentes fontes, por exemplo, da entrada do usuário versus renderizada do servidor. No ASP.NET, a técnica funciona muito bem com o conceito de postagem, porque você executa a função de corrigir tudo sempre que renderiza a página.
Agora que eu mencionei que os eventos são perdidos ou repetidos e obtêm o estado de diferentes fontes, acho que é óbvio como essa abordagem mapeia bem para um espaço problemático como o do BitTorrent.
Contras? Bem, o golpe óbvio é que há um impacto no desempenho, porque é menos eficiente revisar tudo o tempo todo. Mas uma solução como o BitTorrent é otimizada para expandir, não para escalar, por isso é bom para esse tipo de coisa. Dependendo do problema que você está tentando resolver, pode não ser adequado para você.
fonte
Eu acho que o artigo é um pouco datado, porque, enquanto eu o li, não é realmente uma idéia heterodoxa ou nova. Essa idéia é apresentada como um padrão separado quando na verdade é apenas uma implementação simples do Observer. Pensando no que estava fazendo na época, lembro-me de trabalhar na lógica para ficar atrás de uma interface um tanto complexa com vários painéis diferentes com dados interdependentes. O usuário pode alterar valores e / ou executar uma rotina de otimização e, com base nessas ações, foram gerados eventos que a interface do usuário ouviria e atualizaria conforme necessário. Houve vários problemas durante o desenvolvimento em que determinados painéis não eram atualizados quando deveriam. A correção (permanecendo dentro do design) era gerar eventos de outros eventos. Por fim, quando tudo estava funcionando corretamente, quase todas as alterações resultaram na atualização de todos os painéis. Toda a complexidade de tentar isolar quando um determinado painel precisava ser atualizado era inútil. E isso não importava de qualquer maneira. Foi efetivamente uma otimização prematura. Eu teria economizado uma tonelada de tempo e esforço simplesmente juntando tudo em um único evento que atualizou tudo.
Existem inúmeros sistemas projetados no "conserte tudo" ou atualize tudo. Pense em todas as interfaces CRUD que adicionam / atualizam uma linha e depois solicitam o banco de dados. Esta não é uma abordagem exótica, é apenas a solução óbvia e não inteligente. Você tem que perceber que em 2003, era o auge da 'febre padrão'. Pelo que pude perceber, as pessoas pensavam que nomear novos padrões seria o caminho para a fama e a riqueza. Não me interpretem mal, acho que o conceito de padrão é extremamente útil para descrever soluções em abstrato. As coisas meio que saíram dos trilhos um pouco. É lamentável, porque criou muito cinismo sobre o conceito de padrão em geral. É apenas neste contexto que faz sentido falar sobre isso como uma solução "não ortodoxa". Isto' é semelhante à ortodoxia em torno de ORMs ou DI containers. Não usá-los é visto como pouco ortodoxo, mesmo que as pessoas estivessem construindo software muito antes de essas ferramentas existirem e, em muitos casos, essas ferramentas são um exagero.
Então, volte para 'consertar tudo'. Um exemplo simples é calcular meios. A solução simples é somar números e dividir pela cardinalidade dos valores. Se você adicionar ou modificar um número, basta fazê-lo novamente, desde o início. Você pode acompanhar a soma e a contagem de números e quando alguém adiciona um número, você aumenta a contagem e a adiciona à soma. Agora você não está adicionando todos os números novamente. Se você já trabalhou com o Excel com uma fórmula que faz referência a um intervalo e modificou um único valor nesse intervalo, você tem um exemplo do padrão 'corrigir tudo', ou seja, qualquer fórmula que tenha uma referência a esse intervalo será recalculada, independentemente de esse valor era relevante (por exemplo, usando algo como sumif ()).
Isso não quer dizer que essa não seja uma escolha inteligente em um determinado contexto. No exemplo médio, digamos que agora precisamos oferecer suporte a atualizações. Agora eu preciso conhecer o valor antigo de alguma forma e apenas alterar a soma pelo delta. Nada disso é realmente tão desafiador até que você considere tentar fazer isso em um ambiente distribuído ou simultâneo. Agora você precisa lidar com todos os tipos de problemas de tempo espinhosos e provavelmente acabará criando um grande gargalo que atrasa as coisas muito mais do que recalcular.
O resultado aqui é que a abordagem 'conserte tudo' ou 'atualize tudo' é muito mais fácil de acertar. Você pode fazer com que uma abordagem mais sofisticada funcione, mas é muito mais complicada e, portanto, tem mais chances de ser falha. Além disso, em muitos contextos, a abordagem 'atualizar tudo' pode ser mais eficiente. Por exemplo, as abordagens de cópia em gravação geralmente são mais lentas para abordagens de encadeamento único, mas quando você tem alta simultaneidade, pode evitar bloqueios e, portanto, fornecer melhor desempenho. Em outros casos, pode permitir que você faça alterações em lote de maneira eficiente. Portanto, para a maioria dos problemas, você provavelmente deseja começar com uma abordagem de atualizar tudo, a menos que tenha um motivo específico para não fazê-lo e depois se preocupar em fazer algo mais complexo quando precisar.
fonte
Não tenho certeza se é um "padrão de design", mas eu classificaria esse tipo de comportamento como configuração de estado final ou configuração de estado desejada , na veia de Puppet, Chef ou Powershell DSC.
Essas soluções normalmente operam no nível de gerenciamento de sistemas, não no nível da lógica de negócios, como a pergunta descreve, mas são efetivamente o mesmo paradigma e, embora essas ferramentas sejam geralmente de natureza declarativa, os mesmos princípios podem ser aplicados no código de procedimento ou no script.
fonte
Eu tenho usado isso principalmente nas interfaces de usuário. O bom é que você o escreve uma vez e lida com tudo, desde o mais simples ao mais difícil, da mesma forma (por exemplo, se o usuário gira a tela, ou em um laptop / desktop, se o usuário redimensionar uma janela, e praticamente tudo muda )
Não há muitas razões para se preocupar com eficiência. Na interface do usuário, as coisas caras são como redesenhar um item que foi movido. O cálculo de onde cada item vai e qual o tamanho dele é geralmente bastante rápido. Tudo o que você precisa é ter certeza de que, sempre que achar que um item deve permanecer exatamente no lugar a que pertence, nenhum código é executado para movê-lo. As verdadeiras mudanças são todas as coisas que você tinha que fazer de qualquer maneira.
fonte
Soa como princípios de programação reativa. "Corrigir tudo" analisa o estado atual do "núcleo" e propaga tudo o mais que deve ser afetado - "estados computados". Se você otimizar essa derivação, ela poderá atingir alta eficiência, a-la React, se for realizada ingenuamente, o desempenho poderá não ser o ideal, embora ainda possa ser rápido o suficiente.
fonte