Brzmi dość prosto, wiem, ale ostatnio mój kolega powiedział mi, że wywoływana metoda startHttpServer
jest zbyt skomplikowana, aby ją zrozumieć, ponieważ uruchamia serwer tylko wtedy, gdy jeszcze nie działa. Czuję, że wpadam w kłopoty, kiedy odpowiadam: „Poważnie? Robiłem to od dziesięcioleci - to powszechny schemat programowania”. Częściej niż chciałbym przyznać, że powraca z udokumentowanymi dowodami, które pokazują, że cała społeczność programistów stoi za jego punktem widzenia i ostatecznie czuję się zakłopotana.
Pytanie : Czy istnieje udokumentowany wzorzec projektowy za koncepcją metody, która nie działa, jeśli wymagane działanie jest już skuteczne? A może, jeśli nie jest wzorem, ma też nazwę? A jeśli nie, to czy jest jakiś powód, by sądzić, że zbyt skomplikowane jest rozważenie napisania metody w ten sposób?
źródło
startHttpServer
), i tak, tutaj stosuje się określenie „idempotent” dobrze.Odpowiedzi:
Jak już powiedział NickWilliams : koncepcja OP opisana jest jako idempotent (rzeczownik Idempotency ). Jest to rzeczywiście powszechna praktyka, szczególnie w interfejsach API wysokiego poziomu.
ALE: Zmień nazwę funkcji.
Zamiast
startHttpServer
nazywać tomakeSureHttpServerIsRunning
lubensureHttpServerIsRunning
.Po wywołaniu funkcji
startHttpServer
czytelnicy oczekują, że uruchomi serwer HTTP; kiedy zostanie wywołany dziesięć razy z rzędu, będę miał dziesięć serwerów działających. Twoja funkcja nie robi tego przez większość czasu. Dodatkowo nazwa z „start” sugeruje, że jeśli chcę, aby działał tylko jeden serwer, muszę śledzić, czy funkcja została już wywołana, czy nie.Kiedy funkcja jest wywoływana
makeSureHttpServerIsRunning
, zakładam, że wykona niezbędne czynności, aby upewnić się, że serwer HTTP działa, najprawdopodobniej sprawdzając, czy już działa, i uruchamiając go w inny sposób. Zakładam również, że funkcja zapewnia, że serwer faktycznie działa (uruchomienie serwera może zająć trochę czasu, gdy jeszcze nie działa).źródło
Zmień nazwę na
EnsureServerRunning
.Całkowicie jednoznaczne i jasne, że zapewnia, że działa (jeśli nie jest), bez sugerowania ponownego uruchomienia, jeśli tak jest.
(Alternatywnie
StartServerIfNotRunning
:?)źródło
Nie jest to wzorzec projektowy, ale nazwałbym tę metodę idempotentną . Termin ten jest zwykle używany w odniesieniu do połączeń zdalnych, ale opis wydaje się pasować do tego, co robisz.
Efektem ubocznym serwera jest tutaj to, że serwer HTTP jest uruchamiany po wywołaniu metody. Nie widzę nic złego w tej metodzie.
Jeśli potrzebujesz wzorca projektowego, myślę, że możesz udostępnić swój serwer HTTP jako singleton, który jest uruchamiany po zainicjowaniu.
źródło
Jako ten, który wdraża to narzędzie ,
startHttpServer
powinieneś starać się, aby było to najprostsze, płynne i bezproblemowe w użyciu ...Logika funkcji
Technicznie rzecz biorąc, przez rozszczepienie
startHttpServer
jest logika w 2 funkcje i nazywając je oddzielnie , wszystko co robisz jest w ruchustartHttpServer
's idempotentność do kodu wzywając obie funkcje zamiast ... Poza tym, o ile nie zawijać zarówno logikę w trzeciej funkcji (co jest, co robistartHttpServer
po pierwsze), to zmusza cię do napisania nieSUSZONEGO kodu, powielając go wykładniczo wszędzie, gdzie będziesz musiał zadzwonićstartHttpServer
. Krótko mówiąc,startHttpServer
musi nazywać sięisHttpServerRunning
funkcją.Więc mam na myśli:
isHttpServerRunning
funkcję, ponieważ i tak może być potrzebna niezależnie ...startHttpServer
, używając goisHttpServerRunning
do odpowiedniego zdefiniowania następnego działania ...Mimo to możesz
startHttpServer
zwrócić dowolną wartość, której użytkownik tej funkcji może potrzebować, np .:0
=> błąd uruchamiania serwera1
=> serwer rozpoczął sukces2
=> serwer został już uruchomionyNazewnictwo funkcji
Po pierwsze, jaki jest główny cel użytkownika? Aby uruchomić serwer HTTP , prawda?
Zasadniczo nie ma problemu, zamierzając rozpocząć coś, co już rozpoczęto, AKA
1*1=1
. Tak więc, przynajmniej dla mnie, nazwanie go „ensureHttpServerIsRunning
” nie wydaje się konieczne, bardziej zależałoby mi na tym, jak długa, naturalna i niezapomniana jest nazwa funkcji.Teraz, jeśli chcesz wiedzieć, jak szczegółowo działa funkcja pod maską, istnieje do tego dokumentacja lub źródło kodu, mam na myśli, jak w przypadku każdej innej funkcji z biblioteki / frameworka / API / etc ...
Nauczysz się tej funkcji raz, pisząc ją wiele razy ...
W każdym razie trzymałbym się tego,
startHttpServer
co jest krótsze, prostsze i bardziej wyraźne niżensureHttpServerIsRunning
.źródło
Przypuszczam, że twój kolega miał na myśli, że
startHttpServer
robi zbyt wiele:To dwie niepowiązane części kodu. Na przykład podobna sytuacja występuje, gdy aplikacja komputerowa powinna upewnić się, że nie jest uruchomiona po uruchomieniu; będzie część kodu, która obsługuje instancje aplikacji (na przykład za pomocą muteksu) oraz kod, który uruchomi pętlę komunikatów aplikacji.
Oznacza to, że musisz mieć nie jedną, ale co najmniej dwie metody :
isHttpServerRunning: boolean
startHttpServer
Punkt wejścia aplikacji wywoła pierwszą metodę, a następnie drugą, jeśli zwracana jest wartość
false
. Teraz każda metoda robi jedną i jedną rzecz i jest łatwa do zrozumienia.¹ Jeśli logika potrzebna do sprawdzenia, czy serwer już działa, jest zbyt złożona, może wymagać dalszego rozdzielenia na wiele metod.
źródło
startHttpServer
nazywa się więcej niż jedno miejsce w kodzie? Czy wiele podobnych wierszy należy wszędzie wkleić? Czy należy to zrobić ze wszystkimi funkcjami? Już wkrótce twój program będzie miał nieskończony rozmiar.startHttpServer
metody będzie mniej więcej takiif (isHttpServerRunning()){ return; }
. Zapewniasz regułę biznesową, że „uruchomienie serwera HTTP, jeśli już działa”, nie jest prawidłowe, ale nakładasz na kogoś odpowiedzialność za egzekwowanie tej reguły. Ad-hoc i wielokrotnie w każdym miejscu, do którego mogą zadzwonićstartHttpServer
.Ponieważ nie określasz języka, w JavaScript wiele bibliotek ma funkcję „raz”, np . Underscore . Więc jeśli byłoby ci to znane, nazwij to „raz” i prawdopodobnie zmień nazwę swojej metody.
Ja, pochodząc bardziej z Javy, przychodzą mi na myśl określenia „buforowanie” lub „leniwa ocena”. „Idempotent” jest technicznie poprawny i jest dobrym wyborem, szczególnie. jeśli masz bardziej funkcjonalne tło.
źródło
restartHttpServer()
metodę. Ale po prostu się zatrzymuję - jaki jest tam przypadek użycia? Lubisz sporadyczne awarie połączeń? :-)ensureRunning()
? :-) Jeśli chodzi o zatrzymanie go przez administratora, to ciągłe ponowne uruchamianie tego drugiego kodu, gdy administrator próbuje zmodyfikować lub naprawić coś, byłoby niezwykle irytujące i złe. Niech administrator go zrestartuje, a nie kod.Wolę
startHttpServerIfNotIsRunning
.W ten sposób warunek jest wyraźnie wymieniony już w nazwie metody.
Ensure
lubmakeSure
wydaje mi się nieco niejasny, ponieważ nie jest to wyrażenie techniczne. Wygląda na to, że nie wiemy dokładnie, co się wydarzy.źródło
Ensure
znaczy. Nadal nie lubię tego słowa jako technicznego wyrażenia.Ensure
jest czymś ludzkim. System nic nie może zapewnić, zrobi tylko to, co powinien.Twój kolega powinien był ci powiedzieć, że nie masz biznesu piszącego tą metodą. Jest już napisany wiele razy i napisany lepiej, niż można to napisać. Na przykład: http://docs.ansible.com/ansible/latest/systemd_module.html https://docs.saltstack.com/en/latest/ref/states/all/salt.states.service.html
Z architektonicznego punktu widzenia posiadanie dowolnego kodu zarządzającego serwerem WWW to koszmar. Chyba że zarządzanie usługami zależy wyłącznie od kodu użytkownika. Ale zgaduję, że nie napisałeś monit (ani kubernetes lub ...).
źródło
startServer
funkcji lub podobnego jest niczym niezwykłym . To nie znaczy, że napiszesz drobiazgowe szczegóły niskiego poziomu.