O que é o padrão de design “Fix Everything”?

74

Neste artigo de 2003 de Stephen Figgins em linuxdevcenter.com , BitTorrent de Bram Cohen é descrito como usando o padrão de design "Fix Everything".

A less common approach that both makes BitTorrent harder to grasp, but worthy of study, is Cohen's use of idempotence. A process is idempotent when applying it more than once causes no further changes. Cohen says he uses a design pattern he calls "Fix Everything," a function that can react to a number of changes without really noting what all it might change. He explains, "you note the event that happened, then call the fix everything function which is written in this very idempotent manner, and just cleans up whatever might be going on and recalculates it all from scratch." While idempotence makes some difficult calculations easier, it makes things a little convoluted. It's not always clear what a call is going to change, if anything. You don't need to know in advance. You are free to call the function, just to be on the safe side.

Isso soa bem legal em face disso.

No entanto, parece-me que chamar uma função idempotente de "corrigir tudo" melhoraria a robustez do sistema ao custo da eficiência e potencialmente estragaria o sistema que o contém (que pode preferir processos que planejam e executam com cuidado). / p>

Eu não posso dizer que já usei isso antes. Eu também não consigo encontrar a fonte para o seu pedido on-line (mas eu encontrei este que alega ser baseado nele). Nem posso encontrar referências a ele fora deste artigo (e considero meu google-fu muito bom), mas encontrei uma entrada para " Capacidade Idempotente "em SOApatterns.org .

Essa idéia é mais conhecida por outro nome?

Qual é o padrão de design "Corrigir tudo"? Quais são os seus prós e contras?

    
por Aaron Hall 19.04.2017 / 17:32
fonte

5 respostas

100

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:

  1. Escreva um manipulador separado, para cada controle, que responda aos eventos desse controle e atualize outros controles conforme necessário.

  2. Escreva um único manipulador que examine o estado de todos os controles na página e apenas conserte tudo .

A segunda chamada é "idempotente" porque você pode ligar várias vezes e os controles sempre serão organizados corretamente. Considerando que a primeira chamada (s) pode ter problemas se uma chamada for perdida ou repetida, e. 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 "corrigir tudo" conforme necessário "apenas para estar no lado seguro".

A segunda abordagem especialmente agradvel quando o estado pode vir de fontes diferentes, e. da entrada do usuário versus processada pelo servidor. No ASP.NET, a técnica funciona muito bem com o conceito de postback porque você acabou de executar a função de corrigir tudo sempre que renderiza a página.

Agora que eu mencionei eventos sendo perdidos ou repetidos, e obtendo estados de diferentes fontes, estou pensando que é óbvio como essa abordagem mapeia bem para um espaço problemático como o do BitTorrent.

Contras? Bem, o óbvio é que há um impacto no desempenho, porque é menos eficiente passar por cima de tudo o tempo todo. Mas uma solução como o BitTorrent é otimizada para escalar, não escalar, então é bom para esse tipo de coisa. Dependendo do problema que você está tentando resolver, pode não ser adequado para você.

    
por 19.04.2017 / 17:49
fonte
15

Eu acho que o artigo está um pouco datado porque, ao lê-lo, isso não é realmente uma idéia nada ortodoxa ou nova. Essa ideia é apresentada como um padrão separado quando, na verdade, é apenas uma simples implementação do Observador. Pensando no que eu estava fazendo na época, lembro de trabalhar na lógica para me sentar 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 ouve e atualiza conforme necessário. Houve vários problemas durante o desenvolvimento em que determinados painéis não foram atualizados quando deveriam. A correção (permanecendo dentro do design) era gerar eventos de outros eventos. Por fim, quando tudo estava dando certo, quase todas as mudanças resultavam em todos os painéis para atualizar. Toda a complexidade de tentar isolar quando um determinado painel precisava atualizar foi em vão. E isso não importava de qualquer maneira. Foi efetivamente uma otimização prematura. Eu teria economizado muito tempo e esforço simplesmente juntando tudo em um único evento que refrescou tudo.

Existem inúmeros sistemas projetados no "consertar tudo" ou atualizar tudo. Pense em todas as interfaces CRUD que adicionam / atualizam uma linha e, em seguida, voltam a consultar o banco de dados. Esta não é uma abordagem exótica, é apenas a solução óbvia não inteligente. Você tem que perceber que, em 2003, foi o auge da "febre padrão". Pelo que eu poderia dizer, as pessoas achavam que nomear novos padrões seria o caminho para a fama e a riqueza. Não me entenda mal, acho que o conceito de um padrão é extremamente útil para descrever soluções abstratas. As coisas meio que saíram dos trilhos um pouco. É uma pena porque criou muito cinismo sobre o conceito de padrão em geral. É somente nesse contexto que faz sentido falar sobre isso como uma solução "não ortodoxa". É semelhante à ortodoxia em torno de ORMs ou contêineres DI. Não usá-los é visto como heterodoxo, embora as pessoas estivessem construindo software muito antes de essas ferramentas existirem e, em muitos casos, essas ferramentas são exageradas.

Então, de volta 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 adiciona à soma. Agora você não está adicionando novamente todos os números novamente. Se você já trabalhou com o Excel com uma fórmula que referencia 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 isso não seja uma escolha inteligente em um determinado contexto. No exemplo médio, digamos que agora precisamos dar suporte a atualizações. Agora eu preciso saber o valor antigo de alguma forma e apenas alterar a soma pelo delta. Nada disso é realmente tão desafiador até você considerar tentar fazer isso em um ambiente distribuído ou concorrente. Agora você tem que lidar com todos os tipos de problemas espinhosos de tempo e você provavelmente acabará criando um grande gargalo que retarda as coisas muito mais do que recalcular.

O resultado aqui é que a abordagem 'corrigir tudo' ou 'atualizar tudo' é muito mais fácil de acertar. Você pode fazer um trabalho de abordagem mais sofisticado, mas é muito mais complicado e, portanto, mais propenso a ser falho. 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 quer começar com uma abordagem de atualização de tudo, a menos que tenha uma razão específica para não conseguir fazer isso e, em seguida, se preocupe em fazer algo mais complexo quando tiver necessidade. Uma implementação funcional com a qual você pode testar a regressão é valiosa por si só, mesmo que seja lenta.

    
por 19.04.2017 / 19:12
fonte
4

Não tenho certeza se é um "padrão de design", mas 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 em um nível de lógica de negócios como a pergunta descreve, mas é efetivamente o mesmo paradigma e, embora tais ferramentas sejam geralmente de natureza declarativa, os mesmos princípios podem ser aplicados no código procedural ou scripts.

    
por 19.04.2017 / 19:31
fonte
1

Eu usei principalmente isso nas interfaces do usuário. O legal é que você escreve uma vez, e lida com tudo, do mais simples ao mais difícil, igualmente bem (por exemplo, se o usuário roda a tela ou em um laptop / desktop se o usuário redimensiona uma janela e praticamente tudo muda ).

Não há muito motivo para se preocupar com eficiência. Na interface do usuário, as coisas caras são coisas como redesenhar um item que foi movido. O cálculo de onde cada item vai e quão grande é geralmente é bastante rápido. Tudo que você precisa ter certeza é que sempre que você achar que um item deve ficar exatamente no lugar onde ele pertence, nenhum código é executado para movê-lo. As mudanças reais são todas as coisas que você teve que fazer de qualquer maneira.

    
por 29.08.2017 / 01:00
fonte
0

Soa como princípios de programação reativa. "Corrigir tudo" analisa o atual estado "central" e propaga todo o resto que deveria ser afetado - "estados computados". Se você otimizar esta derivação, ela pode alcançar alta eficiência, se ela for feita ingenuamente, o desempenho pode não ser o ideal, embora ainda seja rápido o suficiente.

    
por 28.08.2017 / 21:24
fonte