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?
źródło
This sounds quite nice on the face of it.
Naprawdę? Brzmi okropnie!Odpowiedzi:
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:
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.
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.
źródło
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.
źródło
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.
źródło
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ć.
źródło
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.
źródło