Jak korzystać z pisania kaczego w javascript bez zawsze sprawdzania właściwości i metod?

11

Wiem, że javascript używa pisania kaczego i na początku myślałem, że to ułatwi polimorfizm w porównaniu do silnie pisanych języków, takich jak C #. Ale teraz moje funkcje pobierające argumenty są zaśmiecone takimi rzeczami:

if(myObj.hasSomeProperty())

lub

if(myObj.hasSomeMethod())

lub

if(isNumber(myParam))

itp.

To jest dla mnie naprawdę brzydkie. Pochodzę z tła C # i uważam, że zdefiniowane interfejsy są znacznie lepsze.

Zastanawiam się, czy niepoprawnie próbuję zastosować strategie skuteczne w językach o typie statycznym i czy jest lepszy sposób na wykonanie tego w javascript?

Wiem, że po prostu nie mogłem sprawdzić, ale śledzenie błędów w czasie wykonywania javascript może być koszmarem, ponieważ nie zawsze zdarzają się tam, gdzie błąd występuje w kodzie.

Legion
źródło
2
Myślę, że możesz po prostu grzebać nad naturą dynamicznie pisanego języka. Musisz przyzwyczaić się do sposobu myślenia, że ​​w czasie wykonywania pojawi się wiele błędów zamiast czasu kompilacji. Jeśli czujesz potrzebę sprawdzenia, czy każdy argument jest liczbą w każdej funkcji, która wprowadza liczby, może to stać się dużym obciążeniem (choć może warto, jeśli wysyłasz bibliotekę, której bezpieczeństwo jest najwyższym celem). Dla dowolnej skali uważam, że niezbędne jest po prostu zezwolenie na awarie funkcji, jeśli zostaną przekazane niewłaściwe typy. Zamiast tego bardziej produktywne może być konstruowanie testów.
Tam, gdzie może to pomóc w przeprowadzeniu tych kontroli, aby upewnić się, że typy są zgodne z niezbędnymi wymaganiami dotyczącymi interfejsu (sprawdzanie, czy mają wymagane metody, np.), Znajduje się w twoich najbardziej centralnych i szeroko używanych funkcjach (z niestabilnością = 0 z metryka połączenia eferentowego / aferentnego zapewnia Martin). To powinien być całkiem mały cel. Zazwyczaj istnieje wiele jednorazowych funkcji lokalnych, które są izolowane w zakresie - prawdopodobnie nie potrzebują one tak kompleksowego zestawu kontroli środowiska wykonawczego. Nie kumulują się zbytnio.
Przejdź do skryptu typu. Nadal jest pisany w kaczym stylu, ale obsługuje pisanie statyczne, aby wykryć wiele błędów podczas kompilacji.
CodesInChaos
2
Dotknąłeś największego pojedynczego problemu pisania na kaczce: jego moc wynika z jego słabości. Jeśli chcesz zrobić JavaScript zorientowany obiektowo, po prostu musisz żyć z błędami w czasie wykonywania i mieć nadzieję, że testy jednostkowe znajdą je wkrótce po ich utworzeniu :-(
Ross Patterson
@RossPatterson Problem OP dotyczy pisania dynamicznego, a nie pisania kaczego. Zarówno TypeScript, jak i Go są pisane na klawiaturze, ale unikają problemu z OP. Problem z pisaniem kaczek jest inny, mianowicie, że możesz mieć członków, którzy przejdą test kaczki, ale nie spełnią oczekiwanej umowy.
CodesInChaos

Odpowiedzi:

11

Jak korzystać z pisania kaczego w javascript bez zawsze sprawdzania właściwości i metod?

Proste: nie zawsze sprawdzaj właściwości i metody.

W Ruby to, co nazywasz, nazywa się „pisaniem kurczaków”. W dynamicznie pisanym języku, po prostu ufasz, że osoba dzwoniąca przekazuje ci odpowiedni obiekt. Zadaniem dzwoniącego jest uhonorowanie jego strony kontraktu.

Wiem, że javascript używa pisania kaczego i na początku myślałem, że to ułatwi polimorfizm w porównaniu do silnie pisanych języków, takich jak C #.

Mylisz tutaj wiele prostopadłych osi pisania. Istnieją cztery prostopadłe osie pisania:

  • Kiedy : dynamiczne pisanie (typy nie są znane i sprawdzane do czasu uruchomienia) vs. pisanie statyczne (typy są znane i sprawdzane przed uruchomieniem)
  • Co : pisanie kaczką (typy oparte na zachowaniu ), pisanie strukturalne (typy oparte na strukturze ) i pisanie nominalne (typy oparte na nazwie )
  • Czy ich widzisz? pisanie jawne (typy muszą być jawnie opatrzone adnotacjami) a pisanie niejawne (typy są wywnioskowane)
  • mocne pisanie vs. słabe pisanie - być może zauważyłeś, że nie nadałem temu chwytliwemu tytułowi ani wyjaśnienia w nawiasach, ponieważ w przeciwieństwie do siedmiu powyższych terminów, z których każdy ma jedną powszechnie akceptowaną precyzyjną definicję, te dwa terminy mieć około tuzina częściowo rozpowszechnionych niejasnych definicji, które są sobie przeciwne; najlepiej unikać tych terminów, a jeśli musisz ich użyć, najpierw je dokładnie zdefiniuj

Ponieważ wspomniałeś o C #: najczęściej jest to typowanie statyczne, ale obsługuje typowanie dynamiczne poprzez typ dynamic, to jest typowo typowe, ale typy anonimowe używają typowania strukturalnego, a wzorce składniowe (takie jak składnia rozumienia zapytania LINQ) mogą być argumentowane jako kaczka -typowy lub strukturalny, najczęściej jest jawnie wpisany, ale obsługuje niejawne pisanie argumentów typów ogólnych i zmiennych lokalnych (chociaż wielkość zmiennych lokalnych jest raczej dziwna w porównaniu do większości innych języków, ponieważ nie można po prostu pominąć tego typu, zamiast tego należy nadaj mu wyraźny pseudo-typvar, innymi słowy, jeśli chcesz typ niejawny, musisz to wyraźnie powiedzieć). Jednak to, czy C # jest silnie, czy słabo typowany, zależy od tego, której definicji dwóch terminów używasz, jednak zauważ, że w C # może występować wiele błędów typu środowiska wykonawczego, szczególnie z powodu niebezpiecznej kowariancji macierzy.

Wiem, że po prostu nie mogłem sprawdzić, ale śledzenie błędów w czasie wykonywania javascript może być koszmarem, ponieważ nie zawsze zdarzają się tam, gdzie błąd występuje w kodzie.

Debugowanie nie jest łatwą umiejętnością do nauczenia się. Istnieją jednak techniki ułatwiające debugowanie, np. Saff Squeeze to technika opisana przez Kent Beck, która używa testów i refaktoryzacji do debugowania:

Hit 'em High, Hit' em Low :

Testowanie regresji i wyciskanie Saffa

Kent Beck, Three Rivers Institute

Streszczenie: Aby skutecznie izolować defekt, zacznij od testu na poziomie systemu, a następnie stopniowo dołączaj i przycinaj, aż uzyskasz możliwie najmniejszy test demonstrujący defekt.

Jörg W Mittag
źródło
Ten link trafił mnie, trafił w niski link, otrzymał dla mnie http 500, a komunikat „Strona nie jest już dostępna” jako komunikat zorientowany na człowieka.
joshp
Domena threeriversinstitute.org wydaje się być opuszczona.
Bart van Ingen Schenau,
Cholera. I nie jest nawet archiwizowane na WayBack Machine .
Jörg W Mittag,
W jaki sposób dzwoniący ma honorować swoją stronę umowy? Wygląda na to, że nie ma sposobu na komunikację (w kodzie), jakie powinny być parametry. Każda funkcja ma postać funkcji fname (objParam, objParam, ...). Czy to oznacza, że ​​języki takie jak javascript są całkowicie zależne od zewnętrznej dokumentacji do komunikowania użytkowania?
Legion,
@Legion: dokumentacja, dobre nazewnictwo, zdrowy rozsądek, testy jako specyfikacje behawioralne, czytanie kodu źródłowego, nazywacie go. Zauważ, że tak naprawdę niewiele różni się od słabszych systemów typu, takich jak C # lub Java: Np. Znaczenie zwracanej wartości IComparer<T>.Compare(T, T)jest jasne tylko z dokumentacji, a nie typu. I gdzie w rodzaju java.util.Collections.binarySearch(java.util.List<T>)mówi, że…
Jörg W Mittag
1

Wiem, że po prostu nie mogłem sprawdzić, ale śledzenie błędów w czasie wykonywania javascript może być koszmarem, ponieważ nie zawsze zdarzają się tam, gdzie błąd występuje w kodzie.

Rzeczywiście, typową praktyką jest nie sprawdzanie. Tak, oznacza to, że będziesz otrzymywać błędy javascript, które są zgłaszane gdzie indziej na podstawie rzeczywistego problemu. Ale w praktyce nie uważam tego za duży problem.

Pracując w javascript, ciągle testuję to, co piszę. W większości kodów mam testy jednostkowe, które uruchamiają się automatycznie przy każdym zapisaniu mojego edytora. Kiedy coś niespodziewanie pójdzie nie tak, wiem niemal natychmiast. Mam bardzo mały obszar kodu, w którym mogłem popełnić błąd, ponieważ prawie zawsze jest to ostatnia dotykana przeze mnie pomyłka.

Kiedy pojawia się błąd czasu wykonywania, przynajmniej mam ślad stosu, aw przypadku błędu w przeglądarce mam możliwość przejścia do dowolnego poziomu śladu stosu i sprawdzenia zmiennych. Zazwyczaj łatwo jest prześledzić, skąd pochodzi zła wartość, a tym samym przywrócić pierwotny problem.

Jeśli jesteś podobny do mnie, kiedy pisałem głównie w językach o typie statycznym, pisałem większe bloki kodu przed testowaniem i nie miałem praktyki w odszukiwaniu wartości, skąd ona pochodzi. Programowanie w języku takim jak javascript jest inne, musisz używać różnych umiejętności. Podejrzewam, że takie programowanie wydaje się o wiele trudniejsze, ponieważ nie są to umiejętności, które rozwinąłeś pracując w innych językach, takich jak C #.

Powiedziawszy to, myślę, że wiele można powiedzieć o typach wyraźnych. Doskonale nadają się do dokumentacji i wczesnego wychwytywania błędów. Myślę, że w przyszłości będziemy obserwować coraz większą popularność takich rzeczy jak Flow i Typescript, które dodają statyczne sprawdzanie typu do javascript.

Winston Ewert
źródło
0

Myślę, że postępujesz właściwie, musisz tylko znaleźć styl, który będzie bardziej przyjemny dla oka. Oto kilka pomysłów:

  • Zamiast if(myObj.hasSomeProperty())ciebie możesz użyć if( myobj.prop !== undefined ). To BTW będzie działać tylko w trybie ścisłym, w trybie ścisłym, którego będziesz musiał użyć if( typeof myobj.prop !== 'undefined' ).

  • Możesz odciąć część sprawdzania typu do osobnych walidatorów. Ma to tę zaletę, że można pominąć sprawdzanie poprawności, gdy interfejsy są dojrzałe, np. if( is_valid( myobject ))Gdzie is_validzaczyna się if( !DEBUG ) return true;.

  • Czasami ma sens klonowanie danych wejściowych do postaci kanonicznej, w którym to przypadku można zebrać różne cele sprawdzania poprawności do funkcji / obiektu klonowania. Dla exmaple, w my_data = Data( myobj, otherstuff )tym Datakonstruktora mógł wygodnie uruchomić wszystkie różne walidacje w centralnym miejscu.

  • Możesz użyć biblioteki, która (przy opłatach za wyniki) usprawni sprawdzanie poprawności typu w coś bardziej eleganckiego. Nawet jeśli nie wybierzesz tej trasy w dłuższej perspektywie, może być dla Ciebie wygodne, abyś płynnie wprowadził Cię w swój własny styl. Niektóre przykłady obejmują xtype.js , sprawdzanie typu , validator.js itp.

avnr
źródło