Co to jest wzór „Napraw wszystko”?


74

W tym artykule Stephena Figginsa z 2003 roku na linuxdevcenter.com BitTorrent Bram Cohena opisany jest jako wzorzec projektowy „Napraw wszystko”.

Mniej powszechnym podejściem, które sprawia, że ​​BitTorrent jest trudniejszy do uchwycenia, ale godne przestudiowania, jest stosowanie idempotencji przez Cohena. Proces jest idempotentny, jeśli jego zastosowanie więcej niż jeden raz nie powoduje żadnych dalszych zmian. Cohen mówi, że używa wzorca projektowego, który nazywa „Napraw wszystko”, funkcją, która może reagować na wiele zmian, nie zwracając uwagi na to, co wszystko może zmienić. Wyjaśnia: „zauważasz zdarzenie, które się wydarzyło, a następnie wywołaj funkcję fix all, która jest napisana w ten bardzo idempotentny sposób, i po prostu czyści wszystko, co się dzieje, i wszystko od nowa oblicza”. Podczas gdy idempotencja ułatwia niektóre trudne obliczenia, sprawia, że ​​sprawy są nieco skomplikowane. Nie zawsze jest jasne, co zmieni połączenie, jeśli w ogóle. Nie musisz wiedzieć z góry. Możesz wywołać funkcję,

Na pierwszy rzut oka brzmi to całkiem nieźle.

Wydaje mi się jednak, że wywołanie idempotentnej funkcji „napraw wszystko” poprawiłoby niezawodność systemu kosztem wydajności i potencjalnie zepsuło system zawierający (może to preferować procesy, które dokładnie planują i wykonują).

Nie mogę jednak powiedzieć, że już go używałem. Nie mogę również znaleźć źródła jego aplikacji online (ale znalazłem ten, który twierdzi, że jest na nim oparty). Nie mogę również znaleźć odniesienia do niego poza tym artykułem (i uważam, że moje google-fu jest całkiem dobre), ale znalazłem wpis dla „Idempotent Capability” na SOApatterns.org .

Czy ten pomysł jest lepiej znany pod inną nazwą?

Co to jest wzór „Napraw wszystko”? Jakie są zalety i wady?


4
Podejrzewam, że nazwa jest także odniesieniem do idei stałego punktu funkcji, x = f (x). Bez względu na to, ile razy zastosujesz f do x , wynik jest taki sam. Po uzyskaniu poprawnego wyniku ponowne przetworzenie poprawnego wyniku zwraca ten sam poprawny wynik.
9000

7
Pamiętaj, że każdy może nadać dowolną nazwę dowolnemu, ale nie jest to dobrze znany wzorzec oprogramowania. Idempotencja jest dobrze znaną koncepcją samą w sobie; wygląda na to, że jest tu twórczo wykorzystywany.
Robert Harvey

1
Przypomina mi to, jak zaimplementowano główną pętlę zdarzeń w systemie Mac OS. Była to pojedyncza funkcja, która zareagowała na dowolne zdarzenie i ogólnie miała strukturę umożliwiającą testowanie stanu wszystkich kontrolek i aktualizację całego interfejsu użytkownika w razie potrzeby. Rzeczywiście idempotentny.
Lucas,

3
This sounds quite nice on the face of it. Naprawdę? Brzmi okropnie!
Michael

3
@Michael Nie lubisz menedżerów pakietów? Działają według tej samej koncepcji, tylko na mniejszą skalę: zaznacz, jak chcesz, aby wyglądał system, uruchom „napraw wszystko”, instaluje / usuwa / uaktualnia odpowiednio, ale ma coś do zrobienia tylko wtedy, gdy nastąpią zmiany.
Izkata,

Odpowiedzi:


100

Załóżmy, że masz stronę HTML, która jest dość skomplikowana - jeśli wybierzesz coś w jednym menu rozwijanym, może pojawić się inna kontrolka lub wartości w trzeciej kontrolce mogą się zmienić. Możesz podejść do tego na dwa sposoby:

  1. Napisz osobny moduł obsługi dla każdego elementu sterującego, który reaguje na zdarzenia dotyczące tego elementu sterującego, i w razie potrzeby aktualizuje inne elementy sterujące.

  2. Napisz pojedynczą procedurę obsługi, która sprawdza stan wszystkich kontrolek na stronie i po prostu wszystko naprawia .

Drugie wywołanie jest „idempotentne”, ponieważ można wywoływać je w kółko, a elementy sterujące zawsze będą odpowiednio rozmieszczone. Podczas gdy pierwsze połączenie (-a) może mieć problemy, jeśli połączenie zostanie utracone lub powtórzone, np. Jeśli jeden z pilotów wykona przełączenie.

Logika drugiego wywołania byłaby nieco bardziej niejasna, ale wystarczy napisać tylko jedną procedurę obsługi.

I zawsze możesz użyć obu rozwiązań, nazywając funkcję „napraw wszystko” w razie potrzeby „po prostu dla bezpieczeństwa”.

Drugie podejście jest szczególnie miłe, gdy stan może pochodzić z różnych źródeł, np. Z danych wprowadzanych przez użytkownika w porównaniu z renderowaniem z serwera. W ASP.NET technika bardzo dobrze współgra z koncepcją postback, ponieważ po prostu renderujesz funkcję fix all przy każdym renderowaniu strony.

Teraz, gdy wspomniałem o zagubionych lub powtarzających się zdarzeniach oraz o uzyskaniu stanu z różnych źródeł, myślę, że oczywiste jest, w jaki sposób to podejście dobrze odwzorowuje problematyczną przestrzeń, taką jak BitTorrent.

Cons? Cóż, oczywistą wadą jest to, że jest hit wydajności, ponieważ jest mniej wydajne, aby przejrzeć wszystko przez cały czas. Ale takie rozwiązanie jak BitTorrent jest zoptymalizowane pod kątem skalowania w górę, a nie skalowania, więc jest dobre dla tego rodzaju rzeczy. W zależności od problemu, który próbujesz rozwiązać, może nie być odpowiedni dla Ciebie.


9
Wydaje mi się, że MVC jest typowe dla „Napraw wszystko”: kiedy modyfikujesz model, a następnie przerysowujesz widok od zera, widok jest po prostu całkowicie przerysowany, bez próby odgadnięcia, które części może potencjalnie wpłynąć na działanie.
Matthieu M.

3
Brzmi to zasadniczo jak zasada systemów takich jak Saltstack, Ansible i Nix. Biorąc pod uwagę opis konfiguracji, można teoretycznie doprowadzić kilka różnych systemów do tego samego stanu końcowego.
kojiro

1
@MatthieuM. Reagować , który jest dość popularny na rozwoju frontend, jakby że oprócz tego, że ma wirtualny dom diffing więc tylko aktualizuje prawdziwy DOM z rzeczywistymi zmianami
Izkata

2
@Izkata Nawet bardziej niż React, ta odpowiedź przypomniała mi o Redux.
Kevin,

2
Przydatne może być wskazanie, że „napraw wszystko” i idempotent to różne rzeczy: „napraw wszystko” jest zwykle idempotentny (ale nie musi tak być), a idempotentne operacje nie muszą naprawiać wszystkiego ani nawet mieć wydajności kara - wystarczy dać ten sam wynik, gdy zostanie wykonany dwukrotnie.
Hans-Peter Störr

15

Myślę, że artykuł jest nieco przestarzały, ponieważ kiedy go czytam, nie jest to wcale niekonwencjonalny lub nowy pomysł. Pomysł ten jest przedstawiany jako osobny wzorzec, gdy jest tak naprawdę prostą implementacją Observera. Wracając do tego, co wtedy robiłem, pamiętam pracę nad logiką, aby usiąść za nieco złożonym interfejsem z wieloma różnymi panelami z danymi, które były od siebie zależne. Użytkownik może zmienić wartości i / lub uruchomić procedurę optymalizacji i na podstawie tych działań wygenerowano zdarzenia, których interfejs użytkownika będzie nasłuchiwał i aktualizował w razie potrzeby. Podczas opracowywania pojawiło się wiele problemów, w których niektóre panele nie aktualizowały się, kiedy powinny. Poprawka (pozostawanie w projekcie) polegała na generowaniu zdarzeń z innych zdarzeń. Ostatecznie, zanim wszystko działało poprawnie, prawie każda zmiana powodowała odświeżenie wszystkich paneli. Cała złożoność próby wyizolowania, kiedy dany panel wymagał odświeżenia, była niczym. I tak to nie miało znaczenia. To była przedwczesna optymalizacja. Zaoszczędziłbym mnóstwo czasu i wysiłku, po prostu łącząc to wszystko w jedno wydarzenie, które odświeżyło wszystko.

Istnieje niezliczona ilość systemów zaprojektowanych w „napraw wszystko” lub odświeżyć wszystko. Pomyśl o wszystkich interfejsach CRUD, które dodają / aktualizują wiersz, a następnie wymagają DB. To nie jest egzotyczne podejście, to po prostu oczywiste, niemądre rozwiązanie. Musisz zdać sobie sprawę, że w 2003 roku była to „gorączka wzorca”. Z tego, co mogłem powiedzieć, ludzie myśleli, że nazwanie nowych wzorów będzie ich drogą do sławy i bogactwa. Nie zrozumcie mnie źle, myślę, że koncepcja wzoru jest niezwykle przydatna do opisywania rozwiązań w sposób abstrakcyjny. Po prostu sprawy trochę się zepsuły. Jest to niefortunne, ponieważ wywołało wiele cynizmu w kwestii ogólnej koncepcji wzorca. Tylko w tym kontekście sensowne jest mówienie o tym jako o „niekonwencjonalnym” rozwiązaniu. To' jest podobny do ortodoksji wokół ORM lub pojemników DI. Nieużywanie ich jest postrzegane jako niekonwencjonalne, mimo że ludzie budowali oprogramowanie na długo zanim istniały te narzędzia, aw wielu przypadkach narzędzia te są nadmierne.

Wróćmy więc do „napraw wszystko”. Prostym przykładem są środki obliczeniowe. Najprostszym rozwiązaniem jest zsumowanie liczb i podzielenie przez liczność wartości. Jeśli dodasz lub zmodyfikujesz numer, po prostu zrób to od początku. Możesz śledzić sumę i liczbę liczb, a gdy ktoś doda liczbę, zwiększasz liczbę i dodajesz ją do sumy. Teraz nie dodajesz ponownie wszystkich liczb. Jeśli kiedykolwiek pracowałeś z programem Excel z formułą, która odwołuje się do zakresu i modyfikowałeś pojedynczą wartość w tym zakresie, masz przykład wzorca „napraw wszystko”, tj. Każda formuła, która ma odniesienie do tego zakresu, zostanie ponownie obliczona bez względu na to, czy ta wartość była istotna (np. używając czegoś takiego jak sumif ()).

Nie oznacza to, że nie jest to mądry wybór w danym kontekście. W średnim przykładzie powiedzmy, że musimy teraz wspierać aktualizacje. Teraz muszę jakoś poznać starą wartość i zmienić sumę tylko przez deltę. Nic z tego nie jest tak trudne, dopóki nie rozważysz próby zrobienia tego w środowisku rozproszonym lub współbieżnym. Musisz teraz poradzić sobie z wszelkimi problemami związanymi z terminami i prawdopodobnie stworzysz poważne wąskie gardło, które spowalnia rzeczy znacznie bardziej niż ponowne obliczanie.

Rezultatem jest to, że podejście „napraw wszystko” lub „odśwież wszystko” jest znacznie łatwiejsze do zrobienia. Możesz zastosować bardziej wyrafinowane podejście, ale jest ono o wiele bardziej skomplikowane i dlatego jest bardziej podatne na błędy. Ponadto w wielu kontekstach podejście „odśwież wszystko” może być bardziej wydajne. Na przykład podejścia do kopiowania przy zapisie są zwykle wolniejsze w przypadku podejść jednowątkowych, ale gdy masz wysoką współbieżność, pozwala to uniknąć blokad, a tym samym zapewnić lepszą wydajność. W innych przypadkach może to umożliwić grupowanie zmian w efektywny sposób. Dlatego w przypadku większości problemów prawdopodobnie chcesz zacząć od odświeżenia wszystkiego, chyba że masz konkretny powód, dla którego nie możesz tego zrobić, a następnie martwisz się zrobieniem czegoś bardziej złożonego, gdy zajdzie taka potrzeba.


2
Jestem prawie pewien, że Excel zamierza przeliczyć tylko komórki, które są zależne od zmian, dlatego istnieje sposób, aby uruchomić wszystkie komórki do ponownego obliczenia: superuser.com/questions/448376/… (co, jak sądzę, byłoby „naprawieniem wszystkiego” )
Aaron Hall,

@AaronHall Jeśli tak, to naprawdę zła implementacja. Regularnie obserwuję, jak zużywa 100% 7 procesorów przez 15-30 minut, aby obliczyć np. 60 000 komórek. Obliczenia nie są skomplikowane. Często pisałem programy w języku Python, które potrafią wszystko zrobić w arkuszu w ciągu kilku sekund, w tym uruchamianie języka Python. To było moje najlepsze przypuszczenie, jak to może potrwać tak długo. To może być coś innego. Istnieje również wiele naprawdę starych błędów w programie Excel, które mogą być przyczyną tej funkcji.
JimmyJames,

1
@AaronHall możliwe jest również w przypadku tego użytkownika, że ​​automatyczne obliczanie zostało wyłączone w arkuszu. Często robię to na dużych skoroszytach, ponieważ nie mam 15 minut do stracenia za każdym razem, gdy naciskam klawisz Enter.
JimmyJames,

@AaronHall Myślałem trochę więcej i masz rację. Moje założenia były prawdopodobnie zbyt ogólne. Zaktualizowałem odpowiedź, bardziej skupioną na czymś, w co jestem bardziej pewny siebie.
JimmyJames,

2
@JimmyJames: Chciałem powiedzieć, że najlepsze podejście może się bardzo różnić w zależności od okoliczności, a „naprawić wszystko” można podzielić na „z niecierpliwością naprawiać wszystko przy każdej pojedynczej zmianie” i „leniwie naprawić wszystko po zakończeniu wszystkich zmian „.
supercat

4

Nie jestem pewien, czy jest to „wzorzec projektowy”, ale klasyfikowałbym ten typ zachowania jako konfigurację stanu końcowego lub konfigurację stanu pożądanego , zgodnie z DSC Puppet, Chef lub Powershell.

Rozwiązania te zwykle działają na poziomie zarządzania systemami, a nie na poziomie logiki biznesowej, jak opisuje pytanie, ale jest to faktycznie ten sam paradygmat, i chociaż takie narzędzia mają zazwyczaj charakter deklaratywny, te same zasady mogą być stosowane w kodzie proceduralnym lub skryptach.


1

Najczęściej używałem tego w interfejsach użytkownika. Zaletą jest to, że piszesz go raz i radzi sobie równie dobrze od najprostszego, jak i najtrudniejszego przypadku (na przykład, jeśli użytkownik obraca ekran lub na laptopie / pulpicie, jeśli zmienia rozmiar okna i praktycznie wszystko się zmienia ).

Nie ma wielu powodów do obaw o wydajność. W interfejsie użytkownika drogie rzeczy to np. Przerysowywanie przeniesionego elementu. Obliczenie, gdzie idzie każdy element i jak duży jest, jest zwykle dość szybkie. Musisz tylko upewnić się, że za każdym razem, gdy okaże się, że przedmiot powinien pozostać dokładnie w miejscu, do którego należy, żaden kod nie jest wykonywany, aby go przenieść. Rzeczywiste zmiany to wszystkie rzeczy, które i tak musieliście zrobić.


0

Brzmi jak reaktywne zasady programowania. „Napraw wszystko” patrzy na bieżący stan „rdzenia” i propaguje wszystko inne, na co powinien mieć wpływ - „stany obliczone”. Jeśli zoptymalizujesz to wyprowadzenie, może osiągnąć wysoką wydajność, a-la React, jeśli zrobione naiwnie, wydajność może nie być optymalna, chociaż może być wystarczająco szybka.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.