Qual é o padrão de design "Corrigir tudo"?


74

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?


4
Suspeito que o nome também seja uma referência à idéia do ponto fixo de uma função, x = f (x). Não importa quantas vezes você aplique f para x , o resultado é o mesmo. Depois de obter o resultado correto, reprocessar o resultado correto retorna o mesmo resultado correto.
9000

7
Observe que qualquer pessoa pode dar qualquer nome a qualquer coisa que desejar, mas isso não faz com que seja um padrão de software conhecido. Idempotência é um conceito bem conhecido por si só; parece que está sendo usado de forma criativa aqui.
Robert Harvey

1
Isso me lembra como o Main Event Loop foi implementado no Mac OS. Era uma função única que respondia a qualquer evento e era geralmente estruturada para testar o estado de todos os controles e atualizar a interface do usuário inteira, conforme necessário. Idempotente, de fato.
21717 Lucas

3
This sounds quite nice on the face of it. Realmente? Parece horrível para mim!
Michael

3
@ Michael Você não gosta de gerenciadores de pacotes? Eles funcionam com o mesmo conceito, apenas em uma escala menor: marque como você deseja que o sistema seja, execute "conserte tudo", ele instala / remove / atualiza conforme apropriado, mas só tem algo a fazer se houver alterações.
precisa saber é o seguinte

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 a eventos nesse controle e atualize outros controles conforme necessário.

  2. 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ê.


9
Parece-me que o MVC é típico de "Corrigir tudo": quando você modifica o modelo e redesenha a visualização do zero, a visualização é totalmente redesenhada, sem tentar adivinhar quais partes a ação poderia potencialmente afetar.
Matthieu M.

3
Isso soa essencialmente como o princípio por trás de sistemas como Saltstack, Ansible e Nix. Dada a descrição de uma configuração, você pode, teoricamente, trazer vários sistemas diversos para o mesmo estado final.
Kojiro #

1
@MatthieuM. Reagir , que é bastante popular no desenvolvimento frontend, é assim, exceto que não dom virtual diffing por isso só atualiza o dom real com as mudanças reais
Izkata

2
@ Izkata Ainda mais que React, essa resposta me fez pensar em Redux.
21417 Kevin

2
Pode ser útil salientar que "consertar tudo" e idempotente são coisas diferentes: "consertar tudo" geralmente é idempotente (mas não precisa ser), e operações idempotentes não precisam consertar tudo ou até ter um desempenho penalidade - apenas dê o mesmo resultado quando executado duas vezes.
Hans-Peter Störr

15

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.


2
Tenho certeza de que o Excel pretende apenas recalcular células que dependem de alterações, e é por isso que existe uma maneira de fazer com que todas as células recalculem: superuser.com/questions/448376/… (que eu suponho que seria um "consertar tudo" )
Aaron Hall

@AaronHall Se isso acontecer, é uma implementação muito ruim. Eu assisto regularmente a consumir 100% de 7 CPUs por 15 a 30 minutos para calcular, por exemplo, 60.000 células. Os cálculos não são complicados. Eu sempre escrevi programas em Python que podem fazer tudo na planilha em alguns segundos, incluindo iniciar o Python. Este foi o meu melhor palpite sobre como poderia demorar tanto tempo. Poderia ser outra coisa, suponho. Há também vários bugs realmente antigos no Excel, que podem ser o motivo desse recurso.
JimmyJames

1
@AaronHall também é possível com esse usuário que o cálculo automático foi desativado na planilha. Costumo fazer isso em grandes pastas de trabalho porque não tenho 15 minutos de sobra cada vez que pressiono enter.
JimmyJames

@AaronHall Pensei um pouco mais e você tem razão. Minhas suposições eram provavelmente muito amplas. Eu atualizei a resposta para me mais focado em algo que eu estou mais confiante no.
JimmyJames

2
@JimmyJames: O ponto que pretendi enfatizar é que a melhor abordagem pode variar muito, dependendo das circunstâncias, e "consertar tudo" pode ser subdividido em "consertar tudo ansiosamente em cada alteração individual" e "consertar preguiçosamente tudo após todas as alterações serem concluídas "
supercat

4

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.


1

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.


0

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.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.