Что такое шаблон проектирования «Все исправить»?

74

В этой статье Стивена Фиггинса, написанной в 2003 году на linuxdevcenter.com , BitTorrent Брэма Коэна описывается как использование шаблона проектирования «Исправить все».

Менее распространенный подход, который затрудняет понимание BitTorrent, но заслуживает изучения, - это использование иденпотентности Коэном. Процесс идемпотентен, если его применять более одного раза, и не вызывает дальнейших изменений. Коэн говорит, что он использует шаблон проектирования, который он называет «Исправить все», функцию, которая может реагировать на ряд изменений, даже не замечая, что все это может изменить. Он объясняет: «Вы замечаете произошедшее событие, а затем вызываете функцию« исправить все », написанную очень идемпотентно, и просто очищаете все, что может происходить, и пересчитываете все это с нуля». Хотя идемпотентность облегчает некоторые сложные вычисления, она делает вещи немного запутанными. Не всегда ясно, что вызов изменит, если что-нибудь. Вам не нужно знать заранее. Вы можете вызвать функцию,

Это звучит довольно мило на первый взгляд.

Однако мне кажется, что вызов идемпотентной функции «исправить все» улучшил бы надежность системы за счет эффективности и потенциально испортил бы содержащуюся систему (что может предпочесть процессы, которые тщательно планируются и выполняются).

Я не могу сказать, что использовал это раньше. Я также не могу найти источник его приложения в Интернете (но я нашел этот, который утверждает, что основан на нем.). Кроме того, я не могу найти ссылку на нее за пределами этой статьи (и я считаю, что мое google-fu довольно неплохо), но я нашел запись о «Идемпотентной способности» на SOApatterns.org .

Эта идея более известна под другим именем?

Что такое шаблон проектирования «Все исправить»? Каковы его плюсы и минусы?

Аарон Холл
источник
4
Я подозреваю, что имя также является ссылкой на идею неподвижной точки функции, x = f (x). Независимо от того, сколько раз вы примените f к x , результат будет одинаковым. Как только вы достигли правильного результата, повторная обработка правильного результата возвращает тот же правильный результат.
9000
7
Обратите внимание, что любой может дать любое имя любому желаемому, но это не делает его широко известным программным шаблоном. Идемпотентность - само по себе известное понятие; это просто выглядит так, как будто оно используется здесь творчески.
Роберт Харви,
1
Это напоминает мне о том, как цикл главных событий был реализован в Mac OS. Это была единственная функция, которая реагировала на любое событие и была в целом структурирована для проверки состояния всех элементов управления и обновления всего пользовательского интерфейса по мере необходимости. Идемпотент, действительно.
Лукас
3
This sounds quite nice on the face of it. В самом деле? Это звучит ужасно для меня!
Майкл
3
@Michael Вам не нравятся менеджеры пакетов? Они работают по одной и той же концепции, но в меньшем масштабе: пометьте, как вы хотите, чтобы система выглядела, запустите «исправить все», она при необходимости установит / удалит / обновит, но только применительно к изменениям.
Изката,

Ответы:

100

Допустим, у вас есть HTML-страница, которая довольно сложна - если вы выбираете что-то в одном раскрывающемся меню, может появиться другой элемент управления или значения в третьем элементе управления могут измениться. Есть два способа приблизиться к этому:

  1. Напишите отдельный обработчик для каждого элемента управления, который отвечает на события в этом элементе управления и обновляет другие элементы управления по мере необходимости.

  2. Напишите один обработчик, который просматривает состояние всех элементов управления на странице и просто исправляет все .

Второй вызов является «идемпотентным», потому что вы можете вызывать его снова и снова, и элементы управления всегда будут расположены правильно. В то время как первый вызов (вызовы) может иметь проблемы, если вызов потерян или повторен, например, если один из обработчиков выполняет переключение.

Логика второго вызова была бы немного более непонятной, но вам нужно написать только один обработчик.

И вы всегда можете использовать оба решения, вызывая функцию «все исправить» по мере необходимости, «чтобы быть в безопасности».

Второй подход особенно полезен, когда состояние может поступать из разных источников, например, из пользовательского ввода по сравнению с отображением с сервера. В ASP.NET этот метод очень хорошо сочетается с концепцией обратной передачи, потому что вы просто запускаете функцию исправления всего, когда визуализируете страницу.

Теперь, когда я упомянул о потерянных или повторяющихся событиях и получении состояния из разных источников, я думаю, что очевидно, как этот подход хорошо отображается в проблемном пространстве, таком как BitTorrent.

Минусы? Ну, очевидным минусом является то, что производительность снижается, потому что все время обходиться менее эффективно. Но такое решение, как BitTorrent, оптимизировано для масштабирования, а не масштабирования, поэтому оно хорошо для такого рода вещей. В зависимости от проблемы, которую вы пытаетесь решить, она может не подойти вам.

Джон Ву
источник
9
Мне кажется, что MVC типичен для «Fix Everything»: когда вы модифицируете модель, затем перерисовываете представление с нуля, представление просто полностью перерисовывается, не пытаясь определить, на какие части это действие могло потенциально повлиять.
Матье М.
3
По сути, это звучит как принцип, лежащий в основе таких систем, как Saltstack, Ansible и Nix. Учитывая описание конфигурации, вы можете теоретически привести несколько разнородных систем в одно и то же конечное состояние.
Кодзиро
1
@MatthieuM. React , который довольно популярен в разработке веб-интерфейсов, подобен этому, за исключением того, что он делает виртуальный dom diffing, поэтому он только обновляет реальный dom с фактическими изменениями
Izkata
2
@Izkata Даже больше, чем React, этот ответ заставил меня задуматься о Redux.
Кевин
2
Может быть полезно указать, что «исправить все» и идемпотент - это разные вещи: «исправить все» обычно идемпотентно (но не обязательно), а идемпотентным операциям не нужно исправлять все или даже иметь производительность штраф - просто дать тот же результат, когда выполняется дважды.
Ганс-Петер Стёрр
15

Я думаю, что статья немного устарела, потому что, когда я ее читаю, это вовсе не неортодоксальная или новая идея. Эта идея представлена ​​в виде отдельного шаблона, когда она на самом деле является простой реализацией Observer. Вспоминая то, что я делал в то время, я помню, как работал над логикой, чтобы сидеть за довольно сложным интерфейсом с множеством различных панелей с данными, которые были взаимозависимы. Пользователь может изменить значения и / или запустить процедуру оптимизации, и на основе этих действий генерируются события, которые пользовательский интерфейс будет прослушивать и обновлять по мере необходимости. Во время разработки был ряд проблем, когда некоторые панели не обновлялись, когда должны были. Исправление (оставаясь в дизайне) состояло в том, чтобы генерировать события из других событий. В конце концов, к тому времени, когда все заработало, почти каждое изменение привело к обновлению всех панелей. Вся сложность попытки выделить нужную панель для обновления была напрасной. И все равно это не имело значения. Это была преждевременная оптимизация. Я бы сэкономил массу времени и усилий, просто сложив все это в одно событие, которое обновило бы все.

Существуют бесчисленные системы, разработанные для «все исправить» или «обновить все». Подумайте обо всех интерфейсах CRUD, которые добавляют / обновляют строку, а затем запрашивают БД. Это не экзотический подход, это просто очевидное неумное решение. Вы должны понять, что в 2003 году это была вершина «шаблонной лихорадки» Исходя из того, что я мог сказать, люди думали, что присвоение новых образцов будет их путем к славе и богатству. Не поймите меня неправильно, я думаю, что концепция шаблона чрезвычайно полезна для описания решений абстрактно. Вещи просто немного сошли с рельсов. Это прискорбно, потому что это вызвало большой цинизм в отношении концепции паттерна в целом. Только в этом контексте имеет смысл говорить об этом как о «неортодоксальном» решении. Это' Схожи с ортодоксальностью вокруг ORM или DI-контейнеров. Неиспользование их считается неортодоксальным, даже несмотря на то, что люди создавали программное обеспечение задолго до того, как эти инструменты появились, и во многих случаях эти инструменты излишни.

Итак, вернемся к «исправить все». Простым примером является расчет средств. Простое решение состоит в суммировании чисел и делении на количество значений. Если вы добавляете или изменяете число, вы просто делаете это снова, с самого начала. Вы можете отслеживать сумму и количество чисел, а когда кто-то добавляет число, вы увеличиваете количество и добавляете его к сумме. Теперь вы не добавляете все цифры снова. Если вы когда-либо работали с Excel с формулой, которая ссылается на диапазон, и изменили одно значение в этом диапазоне, у вас есть пример шаблона «исправить все», то есть любая формула, которая имеет ссылку на этот диапазон, будет пересчитываться независимо от того, это значение было релевантным (например, используя что-то вроде sumif ()).

Нельзя сказать, что это не разумный выбор в данном контексте. В среднем примере, скажем, нам теперь нужно поддерживать обновления. Теперь мне нужно как-то узнать старое значение и только изменить сумму на дельту. Ничто из этого не является таким сложным, пока вы не решите попытаться сделать это в распределенной или параллельной среде. Теперь вам нужно решить все острые проблемы времени, и вы, скорее всего, в конечном итоге создадите серьезное узкое место, которое замедляет вещи гораздо больше, чем пересчет.

В результате, подход «исправить все» или «обновить все» гораздо проще понять. Вы можете сделать более сложный подход, но он намного сложнее и, следовательно, с большей вероятностью будет ошибочным. Кроме того, во многих случаях подход «обновить все» может быть более эффективным. Например, подходы копирования при записи обычно медленнее для однопоточных подходов, но когда у вас высокий параллелизм, это может позволить вам избежать блокировок и, следовательно, обеспечить лучшую производительность. В других случаях это может позволить вам эффективно объединять изменения в пакет. Поэтому для большинства проблем вы, вероятно, захотите начать с подхода обновления всего, если только у вас нет конкретной причины, по которой вы не можете это сделать, а затем беспокоиться о том, чтобы сделать что-то более сложное, когда у вас возникнет такая необходимость.

JimmyJames
источник
2
Я уверен, что Excel намеревается пересчитать только те ячейки, которые зависят от изменений, поэтому есть способ запустить все ячейки для пересчета: superuser.com/questions/448376/… (который, я полагаю, будет «исправить все») )
Аарон Холл
@AaronHall Если это так, это действительно плохая реализация. Я регулярно смотрю, как он потребляет 100% из 7 процессоров в течение 15-30 минут, чтобы вычислить, например, 60 000 ячеек. Расчеты не сложны. Я часто писал программы на Python, которые могут сделать все на листе за несколько секунд, включая запуск Python. Это было мое лучшее предположение о том, как это может занять так много времени. Это может быть что-то еще, я полагаю. В Excel также есть ряд действительно старых ошибок, которые могут быть причиной этой функции.
JimmyJames
1
@AaronHall также возможно с этим пользователем, что автоматический расчет был отключен на листе. Я часто делаю это на больших книгах, потому что у меня не остается 15 минут, чтобы сэкономить каждый раз, когда я нажимаю клавишу ввода.
JimmyJames
@AaronHall Я подумал немного больше, и у вас есть точка. Мои предположения были, вероятно, слишком широкими. Я обновил ответ, чтобы больше сосредоточиться на чем-то, в чем я более уверен.
JimmyJames,
2
@JimmyJames: Я хотел сказать о том, что лучший подход может сильно варьироваться в зависимости от обстоятельств, и «исправить все» можно подразделить на «быстро исправить все при каждом отдельном изменении» и «лениво исправить все после завершения всех изменений» ».
суперкат
4

Не уверен, что это «шаблон проектирования», но я бы классифицировал этот тип поведения как конфигурацию конечного состояния или желаемую конфигурацию состояния в духе Puppet, Chef или Powershell DSC.

Эти решения обычно работают на уровне управления системами, а не на уровне бизнес-логики, как описано в вопросе, но это фактически та же самая парадигма, и хотя такие инструменты обычно носят декларативный характер, те же принципы могут применяться в процедурном коде или сценариях.

Dan1701
источник
1

Я в основном использовал это в пользовательских интерфейсах. Приятно, что вы пишете один раз, и он одинаково хорошо обрабатывает все, от самого простого до самого сложного (например, если пользователь поворачивает экран, или на ноутбуке / настольном компьютере, если пользователь изменяет размеры окна, и практически все меняется ).

Нет особых причин беспокоиться об эффективности. В пользовательском интерфейсе дорогими являются такие вещи, как перерисовка перемещенного элемента. Расчет того, куда идет каждый предмет и насколько он велик, обычно довольно быстр. Все, что вам нужно убедиться, это то, что всякий раз, когда вы обнаруживаете, что элемент должен оставаться именно в том месте, где он находится, не выполняется никакого кода для его перемещения. Настоящие изменения - это все, что вам пришлось делать в любом случае.

gnasher729
источник
0

Похоже, принципы реактивного программирования. «Исправить все» просматривает текущее состояние «ядра» и распространяет все остальное, на что должно быть оказано влияние - «вычисленные состояния». Если вы оптимизируете этот вывод, он может достичь высокой эффективности, а-ля React, если все сделано наивно, производительность может быть неоптимальной, хотя все еще может быть достаточно быстрой.

orip
источник