Czy śledzenie małp jest uważane za dobrą praktykę programowania?

15

Miałem wrażenie, że monkeypatching jest bardziej w kategorii szybkiego i brudnego hacka, niż w standardowej dobrej praktyce programowania. Chociaż od czasu do czasu używałem do naprawy drobnych problemów z bibliotekami stron trzecich, uważałem to za tymczasowe i przesyłam odpowiednią łatkę do projektu strony trzeciej.

Jednak widziałem tę technikę jako „normalną drogę” w projektach głównego nurtu, na przykład w gevent.monkeymodule Geventa .

Czy monkeypatching stał się głównym nurtem, normalną, akceptowalną praktyką programowania?

Zobacz także: „Monkeypatching For Humans” Jeffa Atwooda

vartec
źródło
13
Powiedziałbym, że łatanie małp NIE jest uważane za dobrą praktykę programowania. Nawet nie wiedząc, co to jest, tylko z nazwy.
littleadv
Co się stanie, jeśli firma zewnętrzna nie chce wykonać potrzebnej poprawki?
1
@ Thorbjørn: dobre pytanie, z jednej strony nie lubię monkeypatchingu, z drugiej nie podoba mi się pomysł klonowania projektu i utrzymywania lokalnych łat, jeśli to tylko drobny problem.
vartec
1
@littleadv: ... nazwij to „hot fix” / „on-the-fly fix” lub „runtime fix” i brzmi dobrze, prawda? ;) To wszystko jest takie samo.
Dagnelies
3
javascript jest zbudowany w dużej mierze wokół tej koncepcji
ZJR

Odpowiedzi:

19

Nie, ale czasami małpa jest mniejszym złem (niż złamanie kodu :)). Moje ogólne zasady dotyczące małp w rubinie to:

  • ma naprawdę dobry powód dla łaty małp (tymczasowa krytyczna poprawka jest dobrym powodem. Ładne formatowanie metody to_s nie jest, chyba że pracujesz na ActiveSupport)

  • uczyń je tak przejrzystymi, jak to możliwe: umieść je w określonym miejscu w bazie kodu i osobnych plikach, napisz dokumentację opisującą powód monkeypatch (oto przykład ).

  • łatwe do usunięcia - dokumentacja powinna zawierać informacje o usuwaniu i na co uważać. Wiele małp jest tymczasowych, więc powinny być łatwe do usunięcia.

Lukas Stejskal
źródło
11

Tak, monkeypatching jest bardzo przydatny!

Jakoś imiona wydają się mieć duży wpływ na postrzeganie ludzi. Nazwij to „monkeypatch” i brzmi źle, nazwij to „hot fix” lub „on-the fix” i brzmi dobrze.

Niezależnie od tego uważam, że możliwość zmiany metod / atrybutów / funkcji w czasie wykonywania jest bardzo przydatną rzeczą. Nawet javascript używają go przez cały dzień, nie wiedząc o tym.

Na przykład:

button.onclick = function(e) { ...}

Ta prosta linia ilustruje fakt, że zmieniasz zachowanie przycisku. Zostało tak zaprojektowane. Podobnie możesz zmienić każdą inną funkcję, ale byłoby to niemądre.

A teraz pytanie dotyczące dostarczania łat w ten sposób ... no cóż ... dlaczego nie. Musisz tylko pobrać małą łatkę zamiast dużej wersji. Cholera, możesz nawet załatać serwer bez zatrzymywania go, świetnie! A pewnego dnia możesz także pobrać najnowszą wersję, aby uzyskać większą aktualizację. Słusznie. Tak więc głosuję na „łaty czasu wykonywania” jako dobrą rzecz.

Co ciekawe, niektóre języki, takie jak Erlang, były nawet oparte na tej koncepcji. Możliwość aktualizacji serwera w locie.

Oczywiście ostatecznie i podobnie jak we wszystkich innych kwestiach, zależy od tego, jak z niego korzystasz. Możesz robić wspaniałe rzeczy OO i gówno, wszystko jest takie samo.

EDYTOWAĆ:

Pozwól, że dodam pewne rozróżnienie spraw, niezależnie od tego, czy łatasz własną bibliotekę, czy bibliotekę innej firmy .

... w zasadzie to, co robisz z taką łatką, naprawia błąd w bibliotece własnej lub innej firmy . W obu przypadkach jest to przydatne. Na własną rękę pozwala ci to naprawić w locie. W przypadku strony trzeciej albo czekasz (kilka miesięcy?), Aż sami to naprawią, albo robisz to teraz samodzielnie. (nadal możesz przesłać im łatkę, aby naprawili ją po swojej stronie). Po wydaniu kolejnej wersji lib z naprawionym problemem nadal możesz, jeśli chcesz zaktualizować bibliotekę i usunąć łatkę po swojej stronie.

Teraz, oczywiście, jeśli użyjesz łatki, aby zmienić zachowanie lib i zrazić jego cel / sposób działania, to oczywiście jest to przepis na katastrofę. Nawet małpa to zobaczy ... mam nadzieję. ;)

Dagnele
źródło
1
Nikt nie mówi, że to nie jest przydatne. Jednak ogólnie nie jest to dobra praktyka. A „poprawka” i „poprawka w locie” nie brzmią dla mnie lepiej.
Lukas Stejskal
1
Cóż, uważam, że możliwość zmiany zachowania aplikacji w locie jest bardzo przydatna, a nawet bardziej, jeśli jest duża. Heck, możesz nawet mieć kod przechowujący starą metodę jako kopię zapasową i polecenie automatycznego przywracania na żądanie! Możliwości są ogromne!
Dagnelies
Zgadzam się, że jest to potężna i przydatna funkcja. Ale także bardzo niebezpieczny (szczególnie w Ruby), dlatego należy go używać z najwyższą ostrożnością (szczególnie w przypadku modyfikacji bibliotek standardowych i bibliotek innych firm). Czy kiedykolwiek próbowałeś utrzymać aplikację w zależności od kilku małpich bibliotek zewnętrznych? Przepis na katastrofę przy każdej próbie aktualizacji biblioteki.
Lukas Stejskal
1
Tak, zgadzam się, jeśli użyjesz tych łatek niedbale, w niezamierzony sposób lub wykorzystując je, może to szybko popsuć. Jak możesz nadużyć dowolnej koncepcji lub zepsuć czymkolwiek. Jednak w przeciwnym razie, jeśli są dobrze zorganizowane i przejrzyste, a wszystkie płyną w następnym dużym wydaniu, dla mnie wygląda to na czyste. ... jednak nie mam doświadczenia z bibliotekami ruby, które są mocno załatane.
Dagnelies
... dodałem kilka uwag na temat tego drugiego przypadku.
Dagnelies
8

Uważam, że wszystkie łatki są z natury ryzykowne ze względu na ich charakter wykonawczy i niemożność złapania w czasie projektowania.

Przyjmują wyjątki czasu wykonywania i wymagają tylko złożonych debuggerów i zegarków.

Są używane, gdy ludzie SEAL klas, a więc dziedziczenie jest niemożliwe. Istnieją jednak lepsze sposoby rozszerzania obiektów bez ich uszkadzania.

Moje dwa centy

Mickey Perlstein
źródło
4

Ogólnie łatanie powinno być ostatecznością, a jeszcze bardziej łatanie małp. Chodzi przede wszystkim o łatwość konserwacji.

Dawno temu, moje jądro Linuksa miało na sobie 3 oddzielne łaty, niezbędne dla mojego sterownika karty graficznej i dwóch zastrzeżonych aplikacji, które miałem. Dwie z nich miały sprzeczne zmiany, co oznaczało, że potrzebowałem czwartej łatki, aby rozwiązać różnice między nimi. Teraz, ilekroć problem bezpieczeństwa został naprawiony w jądrze nadrzędnym, albo musiałem czekać, aż dostawcy tych 3 łat wydadzą aktualizację do nowej wersji jądra, co trwało od jednego do sześciu miesięcy, lub musiałem ręcznie utrzymywać nadrzędny łatki bezpieczeństwa, dopóki inni dostawcy łatek nie nadrobią zaległości.

Po kilku latach dostawcom udało się włączyć do źródłowego źródła jądra i udało mi się zatrzymać proces równoważenia, ale widać, jaki był bałagan w międzyczasie. Nie narzucaj tego swoim programistom, chyba że musisz.

Karl Bielefeldt
źródło
3

Nie. To nie jest standardowa technika tworzenia oprogramowania. Rozwiązanie tego problemu pozostaje nierozwiązane i ma wyraźne wady. Przychodzi na myśl naruszenie zasady substytucji Liskowa . Łatowanie małp znacznie utrudnia rozumowanie programów. W przypadku własnych programów należy umieścić kod tam, gdzie należy. W przypadku bibliotek stron trzecich zawsze będziesz żył w niebezpieczeństwie, że twoja łatka nie będzie działać z następną wersją biblioteki.

Oczywiście łatanie małp jest przydatne, jeśli wiesz, co robisz i nie masz czasu na wdrożenie rozwiązania SOLID . Ale nigdy nie powinieneś uważać tego za standardową technikę i budować łatkę małpy na łatce małpy.

BTW, czy napisałeś kiedyś test jednostkowy dla łaty dla małp?

szalik
źródło
Nie sądzę, że możesz tutaj zastosować LSP. Ma bardzo szczegółową definicję dotyczącą podtypów.
Konrad Rudolph
@KonradRudolph Monkey łatanie obiektu zmienia jego typ. W językach dynamicznie wpisywanych każdy typ t z takim samym interfejsem jak typ u jest podtypem u. Jeśli chodzi jak kaczka ...
szalik
„… Zmienia swój typ” - wystarczy. Ma sens.
Konrad Rudolph
RE „Nie jest to standardowa technika tworzenia oprogramowania”. „Wydaje się, że jest ona wykonywana * cały czas i w głównych bibliotekach” w Pythonie do testowania.
Tommy